J'ai écrit un intercepteur l'autre semaine pour Set qui peut facilement être étendu pour Get, il utilise RealProxy, ce qui signifie que votre classe de base doit dériver de MarshalByRefObject.
Une autre option de fantaisie consiste à avoir un résumé de votre classe et à utiliser Reflection Emit pour construire une classe concrète qui enveloppe toutes les propriétés.
Aussi, vous pouvez regarder des générateurs de code pour contourner ce ou PostSharp ...
Performance pour cette solution n'est pas brillante, mais il devrait être beaucoup plus rapide pour lier l'interface utilisateur. Il pourrait être amélioré en générant des méthodes LCG pour l'invocation de 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() {
}
}
Utilisation:
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);
}
}
Oui, j'essaie d'éviter d'ajouter une vérification à chaque propriété car il y en a plusieurs, et le code est presque le même pour chacune. –