Reputation: 7282
I have a number of objects that all share a common base class, I wish to intercept all calls that set Property values and record if these have been set on a per instance basis.
Can I replace the Set Method of a Property at runtime with Reflection?
Upvotes: 4
Views: 7239
Reputation: 7587
You cannot directly replace it at runtime. If the property is virtual, you can use a DynamicProxy
like Castle's
http://www.castleproject.org/dynamicproxy/index.html
, to create a proxy type for you that extends your type and it's factory can be used to get a class that has a way to intercept it's methods.
Alternatively you can go down the ContextBoundObject
route, or Enterprise Libaries Policy Injection
. http://msdn.microsoft.com/en-us/library/cc511729.aspx
Be warned ContextBoundObject is much slower than Castle's dynamic proxy, but you don't have to declare your methods virtual. Policy Injection only allows you to insert before or after invocation advices, so you can't stop the invocation if you are against it for whatever reason.
If you can deal with doing this as a post compilation step you can use either PostSharp or Mono.Cecil.
I'm personally working on my own Dynamic Proxy that allows replacing methods with Delegates, but its not nearly ready for the lime light.
Upvotes: 0
Reputation: 1063994
One approach there is to make the property virtual, and at runtime create a subclass via reflection-emit that override the properties, adding your code. However, this is advanced, and requires you always make sure to create the subclass (so no "new" in code).
However; I wonder if simply implementing INotifyPropertyChanged and handling the event is simpler. The other option is to just build the handling into the regular class in the first place. There are some ways of making this less repetitive, especially if you have a common base-class where you could add a
protected void SetField<T>(ref T field, T value)
{
if(!EqualityComparer<T>.Default.Equals(field,value))
{
field = value;
// extra code here
}
}
With
private int foo;
public int Foo {
get { return foo; }
set { SetField(ref foo, value); }
}
Upvotes: 6
Reputation: 20471
If your base class derives from ContextBoundObject
you can create your objects in a different Context (within the same AppDomain
) and intercept method calls (which is what properties are) and insert your own message sink into the remoting sink chain.
heres one example
http://www.codeproject.com/KB/cs/aspectintercept.aspx
Upvotes: 1