如何监测无控制权的第三方类的属性变更?
监测非自定义类属性变化的可行方案
如果你没法修改第三方类的代码,又不想用定时器轮询,下面几种方案可以试试:
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
相关产品推荐
相关产品推荐

