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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 13:37:33