C#中Action<T>方法优化需求:仅获取Select方法输入的变更属性而非完整WeatherForecast类实例
优化C# Select方法以仅捕获修改的属性
你的核心需求是仅捕获Action委托中实际修改的WeatherForecast属性,而不是默认遍历所有属性触发变更通知。当前实现不管委托有没有修改属性都会处理全部属性,显然不符合预期。下面提供两种实用的解决方案:
方案一:初始值对比法(快速适配现有代码)
这个思路很直观:先记录实例所有属性的初始值,执行委托后对比找出变化的属性,只处理这些变更项。
实现代码
public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string Summary { get; set; } } public void method(){ Select(d=> { d.Summary = "dasd"; d.TemperatureC = 25; }); } private void Select(Action<WeatherForecast> func) { var result = new WeatherForecast(); // 提前记录所有可读写属性的初始值(排除只读的计算属性TemperatureF) var initialValues = result.GetType().GetProperties() .Where(p => p.CanRead && p.CanWrite) .ToDictionary(p => p.Name, p => p.GetValue(result)); // 执行委托修改属性 func(result); // 对比找出真正变更的属性 var changedProperties = result.GetType().GetProperties() .Where(p => p.CanRead && p.CanWrite) .Where(p => !Equals(initialValues[p.Name], p.GetValue(result))) .ToList(); // 只触发变更属性的通知,也可以在这里收集属性和对应值 foreach (var prop in changedProperties) { RaisePropertyChanged(prop.Name); // 若需要收集值:var changedValue = prop.GetValue(result); } }
注意事项
- 自动排除了只读的计算属性
TemperatureF,如果需要在TemperatureC变更时同步触发它的通知,可以在找到TemperatureC变更后手动添加这个属性到变更列表。 - 使用
Equals方法对比值,能正确处理null值和引用类型的变更。
方案二:代理类跟踪修改(更优雅的长期方案)
如果你的业务场景需要更灵活的属性跟踪,或者要处理依赖属性的联动变更,可以创建一个代理类,拦截属性设置操作,直接记录哪些属性被修改了。
实现代码
public class WeatherForecast { public DateTime Date { get; set; } public int TemperatureC { get; set; } public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string Summary { get; set; } } // 代理类,专门用于跟踪属性修改 public class WeatherForecastProxy { private readonly WeatherForecast _realInstance; private readonly HashSet<string> _changedProps = new HashSet<string>(); public WeatherForecastProxy(WeatherForecast realInstance) { _realInstance = realInstance; } public DateTime Date { get => _realInstance.Date; set { _realInstance.Date = value; _changedProps.Add(nameof(Date)); } } public int TemperatureC { get => _realInstance.TemperatureC; set { _realInstance.TemperatureC = value; _changedProps.Add(nameof(TemperatureC)); // 手动标记依赖的计算属性也变更了 _changedProps.Add(nameof(WeatherForecast.TemperatureF)); } } public string Summary { get => _realInstance.Summary; set { _realInstance.Summary = value; _changedProps.Add(nameof(Summary)); } } // 获取所有变更的属性名 public IEnumerable<string> GetChangedProperties() => _changedProps; // 获取真实的WeatherForecast实例 public WeatherForecast GetRealInstance() => _realInstance; } public void method(){ // 委托参数改为代理类 Select(proxy => { proxy.Summary = "dasd"; proxy.TemperatureC = 25; }); } private void Select(Action<WeatherForecastProxy> func) { var realInstance = new WeatherForecast(); var proxy = new WeatherForecastProxy(realInstance); // 执行委托修改代理属性 func(proxy); // 获取所有变更的属性 var changedProperties = proxy.GetChangedProperties(); // 处理变更通知或收集数据 foreach (var propName in changedProperties) { RaisePropertyChanged(propName); // 如需获取值:var value = proxy.GetRealInstance().GetType().GetProperty(propName)?.GetValue(proxy.GetRealInstance()); } }
优势
- 不需要对比初始值,设置属性时直接标记变更,性能更优。
- 可以灵活处理依赖属性的联动,比如
TemperatureF依赖TemperatureC,修改后者时主动标记前者也变更。 - 代码逻辑更清晰,委托操作的是代理类,明确知道哪些属性会被跟踪。
总结
如果只是临时适配现有代码,方案一的初始值对比法改动小、见效快;如果需要长期维护或处理复杂的属性联动,方案二的代理类方式更可靠。两种方案都能实现你的核心需求:仅获取委托中修改的属性及其值,避免不必要的变更通知。
内容的提问来源于stack exchange,提问作者mohsen ansari
相关产品推荐
相关产品推荐

