我有许多对象都共享一个公共基类,我希望拦截所有设置属性值的调用,并记录这些是否基于每个实例设置。
我可以在运行时用Reflection替换属性的Set方法吗?
答案 0 :(得分:6)
一种方法是将属性设置为虚拟,并在运行时通过reflection-emit创建一个子类,覆盖属性,添加代码。但是,这是先进的,并且需要您始终确保创建子类(因此代码中没有“新”)。
然而;我想知道是否只是简单地实现INotifyPropertyChanged并处理事件更简单。另一种选择是首先将处理构建到常规类中。有一些方法可以减少重复性,特别是如果你有一个可以添加
的公共基类protected void SetField<T>(ref T field, T value)
{
if(!EqualityComparer<T>.Default.Equals(field,value))
{
field = value;
// extra code here
}
}
使用
private int foo;
public int Foo {
get { return foo; }
set { SetField(ref foo, value); }
}
答案 1 :(得分:1)
如果您的基类派生自ContextBoundObject
,您可以在不同的Context(在同一AppDomain
内)和拦截方法调用(属性是什么)中创建对象并插入您自己的消息接收器进入远程接收器链。
这是一个例子
答案 2 :(得分:0)
您无法在运行时直接替换它。如果属性是虚拟的,您可以使用像Castle这样的DynamicProxy
http://www.castleproject.org/dynamicproxy/index.html
,为你创建一个扩展你的类型的代理类型,它的工厂可以用来获得一个方法来拦截它的方法。
或者,您可以沿ContextBoundObject
路线前进,或Enterprise Libaries Policy Injection
。 http://msdn.microsoft.com/en-us/library/cc511729.aspx
警告ContextBoundObject比Castle的动态代理慢得多,但您不必将方法声明为虚拟。 Policy Injection只允许您在调用建议之前或之后插入,因此如果您出于某种原因反对调用,则无法停止调用。
如果您可以将此作为后期编译步骤处理,您可以使用PostSharp或Mono.Cecil。
我个人正在使用我自己的动态代理,它允许用Delegates替换方法,但它还没有准备好用石灰灯。