Design patterns 如何动态实现代理模式?
我正在重温我去年写的类跟踪(肮脏逻辑)。目前,我有一个处理所有状态跟踪的uber基类,但是我需要跟踪的每个属性的值都需要遵循标准的Design patterns 如何动态实现代理模式?,design-patterns,c#-4.0,proxy-pattern,Design Patterns,C# 4.0,Proxy Pattern,我正在重温我去年写的类跟踪(肮脏逻辑)。目前,我有一个处理所有状态跟踪的uber基类,但是我需要跟踪的每个属性的值都需要遵循标准的get{return{return}set{u isDirty=true;_x=value;}工作方式 在玩了实体框架并阅读了之后,我希望有一种更好的方法来实现我的IsDIrty逻辑,同时能够利用自动实现的属性 老实说,我一点也不知道我在说什么。我有没有办法做到以下几点: public class Customer : ITrackable { [TrackS
get{return{return}set{u isDirty=true;_x=value;}
工作方式
在玩了实体框架并阅读了之后,我希望有一种更好的方法来实现我的IsDIrty逻辑,同时能够利用自动实现的属性
老实说,我一点也不知道我在说什么。我有没有办法做到以下几点:
public class Customer : ITrackable
{
[TrackState(true)] // My own attribute
public virtual string Name { get;set;}
[TrackState(true)]
public virtual int Age { get;set;}
// From ITrackable
public bool IsDirty { get; protected set; }
}
然后实现一个动态代理,在使用TrackState
属性设置属性值之前,该代理将使用反射(或另一个神奇的解决方案)首先调用另一个方法
显然,我可以通过创建phyiscal代理类并使用IoC轻松做到这一点:
public class CustomerProxy : Customer
{
Customer _customer;
public override string Name
{
get { return _customer.Name; }
set { IsDirty = true; return _customer.Name; }
}
// Other properties
}
但我不想对每个对象都这样做,否则我现有的解决方案不会有任何好处。希望有人能满足我的好奇心,或者至少告诉我EF是如何做到的。Castle的DynamicProxy正是这样做的: 允许您提供拦截器:
public void Intercept(IInvocation invocation)
{
// Call your other method first... then proceed
invocation.Proceed();
}
您可以通过invocation.Method访问MethodInfo对象。您可以通过设置invocation.ReturnValue来覆盖返回值。您可以访问(并覆盖)参数。可能会有所帮助
或者,如果你喜欢,你可以为此编写自己的IL重写器。这是一个很棒的图书馆,它会让你轻松愉快。这里是快速调制:
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
属性也会有一个setter。完全不相关:killer username,我喜欢,lol.+1谢谢!我的项目中已经有了Castle.Core
,所以我选择了DynamicProxy而不是这个。