2010-12-04 72 views
5

我有大量的对象都共享一个公共基类,我希望截取所有设置属性值的调用并记录是否已经为每个实例设置了这些属性值。在运行时替换属性设置器方法

我可以在运行时用反射替换属性的Set方法吗?

回答

6

一种方法有使虚拟财产,并在运行时创建通过一个子类反射发射,则重写性能,加入您的代码。但是,这是先进的,并且要求您始终确保创建子类(因此代码中没有“新”)。

但是;我想知道是否简单地实现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); } 
} 
+0

这非常接近我现在所拥有的,谢谢。这确实可以完成这项工作,但意味着我必须手动拦截所有呼叫。 – IanNorton 2010-12-06 06:23:07

1

如果您的基类来自ContextBoundObject,您可以在不同的上下文中创建对象(在同一个AppDomain内)并拦截方法调用(这是属性的属性),并将自己的消息接收器插入远程接收器链中。

继承人一例

http://www.codeproject.com/KB/cs/aspectintercept.aspx

+0

这篇文章实在太过分了,但确实强调它可以完成,我会尝试这个但没有属性。谢谢,当我知道更多时,我会发布一些更新。 – IanNorton 2010-12-06 06:28:57

0

在运行时不能直接取代它。如果这个属性是虚拟的,你可以使用一个DynamicProxy,比如Castle的 http://www.castleproject.org/dynamicproxy/index.html ,为你创建一个代理类型来扩展你的类型,它的工厂可以用来获得一个有拦截方法的类。

或者,您可以沿着ContextBoundObject路线或Enterprise Libaries Policy Injection行驶。 http://msdn.microsoft.com/en-us/library/cc511729.aspx

被警告ContextBoundObject比Castle的动态代理慢得多,但是你不必声明你的方法是虚拟的。策略注入只允许你在调用建议之前或之后插入,所以如果你出于任何原因反对它,你不能停止调用。

如果您可以将此操作作为后编译步骤处理,则可以使用PostSharp或Mono.Cecil。

我个人正在使用我自己的动态代理,它允许用代理替换方法,但它几乎没有准备好石灰灯。