【发布时间】:2010-12-07 03:30:47
【问题描述】:
我有许多共享一个公共基类的对象,我希望拦截所有设置属性值的调用,并记录是否已在每个实例的基础上设置了这些值。
我可以在运行时用反射替换属性的 Set 方法吗?
【问题讨论】:
标签: c# reflection
我有许多共享一个公共基类的对象,我希望拦截所有设置属性值的调用,并记录是否已在每个实例的基础上设置了这些值。
我可以在运行时用反射替换属性的 Set 方法吗?
【问题讨论】:
标签: c# reflection
一种方法是使属性虚拟化,并在运行时通过反射发射创建一个覆盖属性的子类,并添加您的代码。但是,这是高级的,并且要求您始终确保创建子类(因此代码中没有“新”)。
但是;我想知道简单地实现 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); }
}
【讨论】:
如果您的基类派生自ContextBoundObject,您可以在不同的上下文中创建您的对象(在同一个AppDomain 中)并拦截方法调用(这是属性)并将您自己的消息接收器插入远程接收器链。
这里有一个例子
【讨论】:
您不能在运行时直接替换它。如果属性是虚拟的,您可以使用 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。
我个人正在开发我自己的动态代理,它允许用委托替换方法,但它还没有准备好成为众人瞩目的焦点。
【讨论】: