Table of Contents

Class AutosaveAttribute

Namespace
Nucs.JsonSettings.Autosave
Assembly
Nucs.JsonSettings.Autosave.dll

Marks a settings class (or a single property) whose setters should commit a save.

[Aspect(Scope.Global)]
[Injection(typeof(AutosaveAttribute))]
[Mixin(typeof(IAutosaveWoven))]
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class AutosaveAttribute : Attribute, IAutosaveWoven
Inheritance
AutosaveAttribute
Implements
Inherited Members

Examples

[Autosave]
public class MySettings : JsonSettings {
    public override string FileName { get; set; } = "config.json";
    public string Name { get; set; }          // no 'virtual' needed
}

var settings = JsonSettings.Load<MySettings>("config.json").EnableAutosave();
settings.Name = "changed";                     // saved

Remarks

This is a compile-time aspect. Applying it causes AspectInjector to append a call to OnPropertySet(object, string) to the end of every instance setter in the annotated scope, in the assembly that declares the class. Nothing is generated at runtime, so this works under Native AOT, where the previous Castle.DynamicProxy implementation could not: DynamicProxy builds proxy types with System.Reflection.Emit, and an AOT binary ships no runtime code generator.

Because there is no proxy, there is also no requirement that properties be virtual, no second object to keep in sync with the loaded one, and no change of type: EnableAutosave() returns the very instance it was given. Ordinary classes, sealed classes and non-virtual properties are all supported.

The attribute is not inherited. Weaving happens where a setter is *declared*, so a property declared on a base class is woven only if that base class carries its own AutosaveAttribute. Apply it to every type in a settings hierarchy that declares properties you want saved.

Writing to a property is not the same as saving: the woven call is inert until EnableAutosave() attaches an AutosaveModule, and it consults that module for the monitored-property set and the suspension state. Marking a class costs nothing until autosave is actually enabled on an instance.

Methods

AfterSetter(object, string)

Appended to every instance setter in the annotated scope.

[Advice(Kind.After, Targets = Target.AnyAccess|Target.Instance|Target.Setter)]
public void AfterSetter(object instance, string propertyName)

Parameters

instance object
propertyName string

Remarks

AspectInjector.Broker.Target.AnyAccess rather than AspectInjector.Broker.Target.Public so that a public string Foo { get; private set; } is covered too; which of the woven setters actually saves is decided at runtime by IsMonitored(string), not by what was woven.

AspectInjector.Broker.Source.Name is resolved at weave time to the property name ("Foo", not "set_Foo") and baked into the call site as a constant, so the advice needs no reflection to identify the member.