You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何监测无控制权的第三方类的属性变更?

监测非自定义类属性变化的可行方案

如果你没法修改第三方类的代码,又不想用定时器轮询,下面几种方案可以试试:

1. 动态代理拦截set操作

用.NET自带的DispatchProxy创建目标对象的代理,拦截属性的set方法来检测变化。示例代码:

public class PropertyChangeProxy<T> : DispatchProxy
{
    private T _target;
    public event Action<string> PropertyChanged;

    protected override object Invoke(MethodInfo targetMethod, object[] args)
    {
        // 识别属性的set方法
        if (targetMethod.IsSpecialName && targetMethod.Name.StartsWith("set_"))
        {
            string propertyName = targetMethod.Name.Substring(4);
            // 获取旧值,执行set后对比触发事件
            var getMethod = typeof(T).GetMethod($"get_{propertyName}");
            var oldValue = getMethod.Invoke(_target, null);
            var result = targetMethod.Invoke(_target, args);
            
            if (!Equals(oldValue, args[0]))
            {
                PropertyChanged?.Invoke(propertyName);
            }
            return result;
        }
        return targetMethod.Invoke(_target, args);
    }

    public static T Create(T target)
    {
        var proxy = Create<T, PropertyChangeProxy<T>>() as PropertyChangeProxy<T>;
        proxy._target = target;
        return (T)(object)proxy;
    }
}

使用的时候把原始对象包装成代理:

var original = new ExampleClass();
var proxy = PropertyChangeProxy<ExampleClass>.Create(original);
proxy.PropertyChanged += propName => 
{
    if (propName == nameof(ExampleClass.SomeNumber))
    {
        Console.WriteLine("SomeNumber变了!");
    }
};
proxy.SomeNumber = 10; // 这一步会触发事件

⚠️ 注意:这个方法要求目标类不是密封类,且属性的get/set方法是虚方法,否则拦截无效。

2. AOP框架织入代码

用PostSharp这类AOP框架,在运行时或编译时给目标类的属性set方法添加监测逻辑。比如写一个切面:

[Serializable]
public class TrackPropertyChange : OnMethodBoundaryAspect
{
    public override void OnExit(MethodExecutionArgs args)
    {
        if (args.Method.IsSpecialName && args.Method.Name.StartsWith("set_"))
        {
            string propName = args.Method.Name.Substring(4);
            var targetObj = args.Instance;
            var getMethod = targetObj.GetType().GetMethod($"get_{propName}");
            var currentValue = getMethod.Invoke(targetObj, null);
            
            Console.WriteLine($"属性{propName}更新为:{currentValue}");
        }
        base.OnExit(args);
    }
}

如果能通过框架配置给第三方类的属性自动加上这个切面,就能直接捕获变化。不过这种方式对项目有一定侵入性,需要熟悉框架的配置。

3. Windows平台用TypeDescriptor(仅限.NET Framework)

在.NET Framework里,可以用TypeDescriptor给属性绑定变更通知:

var obj = new ExampleClass();
var propDesc = TypeDescriptor.GetProperties(obj)["SomeNumber"];
propDesc.AddValueChanged(obj, (sender, e) =>
{
    Console.WriteLine("SomeNumber属性变了");
});
obj.SomeNumber = 20; // 触发通知

这个方法不需要目标类实现任何接口,但在.NET Core/.NET 5+上兼容性不好,仅适合Windows平台的旧项目。

4. Fody自动注入INotifyPropertyChanged

Fody是个.NET代码织入工具,它的PropertyChanged插件可以给任意类(包括第三方类)自动添加INotifyPropertyChanged实现。只要在项目里配置好Fody和插件,编译后目标类的属性变更就会触发PropertyChanged事件,你直接订阅就行。


各方案限制总结

  • 动态代理:要求目标类非密封、属性方法为虚方法;
  • AOP/Fody:需要修改项目编译配置,有一定侵入性;
  • TypeDescriptor:仅适用于.NET Framework,跨平台不支持。

如果以上方案都不符合你的场景,那可能只能用定时器轮询作为兜底方案了。

内容的提问来源于stack exchange,提问作者Tom Crosman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:13:08