PostSharp
我能帮上忙。
或者如果你喜欢的话,你可以为这个写你自己的IL重写器。
Mono.Cecil
class Program {
static ModuleDefinition _module;
static void Main(string[] args) {
// the argument is the assembly path
_module = ModuleDefinition.ReadModule(args[0]);
var trackables = _module.Types.
Where(type => type.Interfaces.Any(tr => tr.Name == "ITrackable"));
var properties = trackables.SelectMany(type => type.Properties);
var trackableProperties = properties.
Where(property => property.CustomAttributes.
Any(ca => ca.Constructor.DeclaringType.Name == "TrackStateAttribute"));
trackableProperties.
Where(property => property.SetMethod != null).
ToList().
ForEach(property => CallIsDirty(property.SetMethod));
_module.Write(args[0]);
}
private static void CallIsDirty(MethodDefinition setter) {
Console.WriteLine(setter.Name);
var isDirty = setter.DeclaringType.Methods.
Single(method => method.Name == "set_IsDirty");
var reference = new MethodReference(isDirty.Name,
_module.Import(typeof(void))) {
DeclaringType = setter.DeclaringType,
HasThis = true,
CallingConvention = MethodCallingConvention.Default
};
reference.Parameters.Add(new ParameterDefinition(
_module.Import(typeof(bool))));
var IL = setter.Body.GetILProcessor();
var param0 = IL.Create(OpCodes.Ldarg_0);
var param1 = IL.Create(OpCodes.Ldc_I4_1);
var call = IL.Create(OpCodes.Call, reference);
IL.InsertBefore(setter.Body.Instructions[0], call);
IL.InsertBefore(setter.Body.Instructions[0], param1);
IL.InsertBefore(setter.Body.Instructions[0], param0);
}
}
它使用以下辅助对象:
public class TrackStateAttribute : Attribute { }
public interface ITrackable { bool IsDirty { get; } }
public class Customer : ITrackable {
[TrackState] public string Name { get; set; }
[TrackState] public int Age { get; set; }
public bool IsDirty { get; protected set; }
}
假设
IsDirty