c# - 有没有办法在设置类的任何属性时调用方法?

标签 c# reflection properties delegates

所以我要做的是在设置 C# 类中的任何属性时调用单个 propertyWasSet() 函数(相反,在获取属性时调用 propertyWasGot() )。我还想知道调用了哪个属性的“get”。

我想维护一个“已设置”属性的字典,并检查“获取”操作是否已设置(如果尚未设置则抛出错误)。

我一直在查看 msdn 文档以了解反射、委托(delegate)等...,但我不完全确定这是否可行。

有没有办法做到这一点?或者在调用可以在基类或其他东西中拦截的这些函数之一时触发事件?

最佳答案

前一周我为 Set 编写了一个拦截器,它可以很容易地为 Get 扩展,它使用 RealProxy,这意味着您的基类需要派生自 MarshalByRefObject。

另一个奇特的选择是让你的类抽象,并使用 Reflection Emit 构造一个包含所有属性的具体类。

您还可以查看代码生成器来解决这个问题或 PostSharp...

此解决方案的性能不是很好,但对于大多数 UI 绑定(bind)来说应该足够快了。它可以通过为代理调用生成 LCG 方法来改进。

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() {
    }

}

用法:

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

    }
}

关于c# - 有没有办法在设置类的任何属性时调用方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/762514/

相关文章:

c# - 使用 C# 将大 (4gb) avi 文件转换为 mpeg 或 mp4 格式

java - 使用 Spring 覆盖外部属性文件中的属性(如果存在)

c# - 带有隐藏输入的 HttpWebRequest 登录

Java 反射 : automatically invoke the right overloaded method based on parameters and signature

c# - 如何从 C# 获取 COM 组件的 ProgID?

java - 使用反射将可见 false 设置为按钮,可以吗?

python - 在模块加载时设置类的属性

python - 数据转换/映射的最佳方法

c# 为什么WebClient通过线程调用时大部分时间都超时?

c# - 在 Windows 身份验证成功后运行 Excel 文件