Ho scritto un intercettatore l'altra settimana per Set che può essere facilmente esteso per Get, utilizza RealProxy, il che significa che la classe base deve derivare da MarshalByRefObject.
Un'altra opzione di fantasia consiste nell'avere estratto la classe e utilizzare Reflection Emit per creare una classe concreta che racchiuda tutte le proprietà.
Inoltre si poteva guardare generatori di codice per aggirare questo o PostSharp ...
prestazioni per questa soluzione non è stellare, ma dovrebbe essere molto veloce per la maggior parte vincolante UI. Potrebbe essere migliorato generando metodi LCG per l'invocazione del proxy.
public interface IInterceptorNotifiable {
void OnPropertyChanged(string propertyName);
}
/// <summary>
/// A simple RealProxy based property interceptor
/// Will call OnPropertyChanged whenever and property on the child object is changed
/// </summary>
public class Interceptor<T> where T : MarshalByRefObject, IInterceptorNotifiable, new() {
class InterceptorProxy : RealProxy {
T proxy;
T target;
EventHandler<PropertyChangedEventArgs> OnPropertyChanged;
public InterceptorProxy(T target)
: base(typeof(T)) {
this.target = target;
}
public override object GetTransparentProxy() {
proxy = (T)base.GetTransparentProxy();
return proxy;
}
public override IMessage Invoke(IMessage msg) {
IMethodCallMessage call = msg as IMethodCallMessage;
if (call != null) {
var result = InvokeMethod(call);
if (call.MethodName.StartsWith("set_")) {
string propName = call.MethodName.Substring(4);
target.OnPropertyChanged(propName);
}
return result;
} else {
throw new NotSupportedException();
}
}
IMethodReturnMessage InvokeMethod(IMethodCallMessage callMsg) {
return RemotingServices.ExecuteMessage(target, callMsg);
}
}
public static T Create() {
var interceptor = new InterceptorProxy(new T());
return (T)interceptor.GetTransparentProxy();
}
private Interceptor() {
}
}
Usage:
class Foo : MarshalByRefObject, IInterceptorNotifiable {
public int PublicProp { get; set; }
public string lastPropertyChanged;
public void OnPropertyChanged(string propertyName) {
lastPropertyChanged = propertyName;
}
}
[Test]
public void TestPropertyInterception() {
var foo = Interceptor<Foo>.Create();
foo.PublicProp = 100;
Assert.AreEqual("PublicProp", foo.lastPropertyChanged);
}
}
fonte
2009-04-17 23:17:45
sì, sto cercando di evitare di aggiungere il controllo di ogni proprietà in quanto ce ne sono diversi, e il codice è quasi lo stesso per ciascuno. –