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(); }
关键修正点:
- 移除了原代码中未定义的
keyValuePair相关错误逻辑,直接通过phases.Select(phase => ...)关联属性和Phase对象 - 修正了
ToDictionary的value生成逻辑,直接提取分组中的Value字段组成列表 - 用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
相关产品推荐
相关产品推荐

