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

C# LINQ技术求助:从Phase集合汇总指定属性生成字典

解决C#中通过LINQ汇总Phase对象指定属性为Dictionary的问题

你的需求是把Phase集合中指定属性的值,按BmkKey(方向+属性名)分组汇总成Dictionary,原代码的主要问题是嵌套LINQ的逻辑混乱,以及最后ToDictionary的写法错误,我帮你修正了代码,同时提供两种实现方案:

方案一:基于反射的灵活实现(适合属性不固定的场景)

这个方案保留你用反射筛选属性的思路,修正了LINQ的逻辑错误:

enum Dir {Up, Dn}
struct BmkKey { public Dir Direction; public string DetailType; }
class Phase {
    public Dir Direction { get; set; }
    public double StartToTerminationBars { get; set; }
    public double StartToTerminationPriceChange { get; set; }
    public double StartToTerminationGa { get; set; }
    public double NotRequiredProperty { get; set; }
}
class PhaseRepo {
    public List<Phase> Phases { get; private set; }
    public List<Phase> GetPhases() {
        return new List<Phase>() {
            new Phase() { Direction = Dir.Up, StartToTerminationBars = 3.0, StartToTerminationPriceChange = 4.0, StartToTerminationGa = 4.0},
            new Phase() { Direction = Dir.Up, StartToTerminationBars = 6.0, StartToTerminationPriceChange = 8.0, StartToTerminationGa = 4.0},
            new Phase() { Direction = Dir.Dn, StartToTerminationBars = 3.0, StartToTerminationPriceChange = -4.0, StartToTerminationGa = -4.0},
            new Phase() { Direction = Dir.Dn, StartToTerminationBars = 6.0, StartToTerminationPriceChange = -8.0, StartToTerminationGa = -4.0},
        };
    }
}
void Main() {
    var phaseRepo = new PhaseRepo();
    var phases = phaseRepo.GetPhases();
    
    // 筛选出需要统计的属性
    var propertiesOfInterest = typeof(Phase).GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Where(prop => prop.Name is "StartToTerminationBars" or "StartToTerminationPriceChange" or "StartToTerminationGa")
        .ToList();

    // 生成目标Dictionary
    var result = propertiesOfInterest
        // 遍历每个属性 + 每个Phase,展开成键值对条目
        .SelectMany(prop => phases.Select(phase => new {
            Key = new BmkKey { Direction = phase.Direction, DetailType = prop.Name },
            Value = (double)prop.GetValue(phase) // 获取当前Phase的该属性值
        }))
        // 按BmkKey分组,把相同方向+属性名的值归为一组
        .GroupBy(item => item.Key)
        // 转换为Dictionary,值是分组后的所有属性值列表
        .ToDictionary(group => group.Key, group => group.Select(item => item.Value).ToList());

    result.Dump();
}

关键修正点:

  1. 移除了原代码中未定义的keyValuePair相关错误逻辑,直接通过phases.Select(phase => ...)关联属性和Phase对象
  2. 修正了ToDictionary的value生成逻辑,直接提取分组中的Value字段组成列表
  3. 用C# 9+的模式匹配简化了属性筛选的判断条件(也可以保留原有的||写法)

方案二:类型安全的非反射实现(适合属性固定的场景)

如果你的目标属性是固定不变的,推荐用这个方案——避免反射的性能开销,同时编译时就能检查错误:

// 其他类/枚举定义和方案一一致,这里只修改Main方法
void Main() {
    var phaseRepo = new PhaseRepo();
    var phases = phaseRepo.GetPhases();

    // 手动定义属性名和对应的取值委托,类型安全
    var propertyMap = new Dictionary<string, Func<Phase, double>> {
        { "StartToTerminationBars", p => p.StartToTerminationBars },
        { "StartToTerminationPriceChange", p => p.StartToTerminationPriceChange },
        { "StartToTerminationGa", p => p.StartToTerminationGa }
    };

    var result = propertyMap
        .SelectMany(kv => phases.Select(phase => new {
            Key = new BmkKey { Direction = phase.Direction, DetailType = kv.Key },
            Value = kv.Value(phase) // 通过委托获取属性值
        }))
        .GroupBy(item => item.Key)
        .ToDictionary(group => group.Key, group => group.Select(item => item.Value).ToList());

    result.Dump();
}

期望输出说明

最终生成的Dictionary<BmkKey, List<double>>会按以下结构呈现:

  • 键BmkKey{Direction=Up, DetailType="StartToTerminationBars"}对应值[3.0, 6.0]
  • 键BmkKey{Direction=Up, DetailType="StartToTerminationPriceChange"}对应值[4.0, 8.0]
  • 以此类推,每个方向+属性名的组合都会汇总对应的所有属性值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:25:56