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
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.