Is there a way to call a method when any property

2019-03-16 09:48发布

So what I'm trying to do is call a single propertyWasSet() function when any property within a C# class is set (conversely, propertyWasGot() when it is get). I would also like to know which property's 'get' was invoked.

I would like to maintain a dictonary of properties that are 'set', and check upon the 'get' action if they have been set yet (and throw an error if it hasn't been).

I've be looking through msdn documentation for reflection, delegates, etc..., but I'm not entirely sure this is possible.

Is there a way to do this? or fire an event upon calling one of these functions that can be intercepted in a base class or something?

5条回答
该账号已被封号
2楼-- · 2019-03-16 10:28

I wrote an interceptor the other week for Set which can easily be extended for Get, it uses RealProxy, which means your base class needs to derive off MarshalByRefObject.

Another fancy option is to have your class abstract, and use Reflection Emit to construct a concrete class that wraps up all the properties.

Also you could look at code generators to get around this or PostSharp...

Performance for this solution is not stellar, but it should be plenty fast for most UI binding. It could be improved by generating LCG methods for proxy invocation.

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);

    }
}
查看更多
三岁会撩人
3楼-- · 2019-03-16 10:33

There's nothing like this if you don't create it yourself.

查看更多
看我几分像从前
4楼-- · 2019-03-16 10:34

I think what you need is very similar to WPF dependency property system. You might want to look at its implementation. Anyhow, you can add the intercepting code to getter and setter of each property too.

查看更多
干净又极端
5楼-- · 2019-03-16 10:35

The SET part of your request is very similar to WPF dependency property system. But the GET part is such unusual that is missing even in the WPF dependency property system!

查看更多
爷、活的狠高调
6楼-- · 2019-03-16 10:39

You may want to look into PostSharp for this sort of task. It is designed to run on top of C# (or any .NET language for that matter) and has the benefit of not cluttering up your code with reflection in addition. In fact, I don't believe you could find a solution that purely uses C#/Reflection without manually adding code to each of your properties, so I would definitely recommend PostSharp as the way to go.

查看更多
登录 后发表回答