如何实现基于动态表达式对List<dynamic>进行分组?
实现动态表达式分组的GenerateGroup方法
我来帮你搞定这个支持动态表达式列表分组的方法,核心思路是把每个传入的表达式编译成可执行的委托,然后用所有表达式的结果组合成唯一的分组键,再基于这个键对集合进行分组。
方法实现代码
首先是GenerateGroup方法的完整实现,它接受List<dynamic>数据源和任意数量的分组表达式:
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; public static class GroupHelper { public static IEnumerable<IGrouping<object, dynamic>> GenerateGroup(List<dynamic> source, params Expression<Func<dynamic, object>>[] groupExpressions) { // 先把所有表达式编译成可直接调用的委托,提升运行效率 var compiledSelectors = groupExpressions.Select(expr => expr.Compile()).ToList(); // 按组合键分组:用匿名类型包装所有表达式的结果,自动实现相等性判断 return source.GroupBy(item => { var keyValues = compiledSelectors.Select(selector => selector(item)).ToList(); return new { Keys = keyValues }; }); } }
关键逻辑说明
- 表达式编译:
Expression<Func<>>是表达式树,需要调用Compile()转换成委托才能执行,这样可以高效获取每个dynamic元素的属性值。 - 分组键设计:用匿名类型包装所有表达式的结果,C#编译器会自动为匿名类型生成
Equals和GetHashCode方法,基于内部属性的值进行判断,完美适配分组的键相等性要求。 - dynamic兼容性:因为是dynamic类型,只要数据源中的元素包含表达式指定的属性(比如
Test、Test2),运行时就能正常获取值;如果元素缺少对应属性,会抛出RuntimeBinderException,可以根据需要添加异常处理逻辑。
调用示例
假设你的数据源是这样的:
var data = new List<dynamic> { new { Test = "GroupA", Test2 = "Value1" }, new { Test = "GroupA", Test2 = "Value1" }, new { Test = "GroupB", Test2 = "Value2" }, new { Test = "GroupB", Test2 = "Value2" }, new { Test = "GroupA", Test2 = "Value1" } };
调用GenerateGroup方法并遍历分组结果:
var groups = GroupHelper.GenerateGroup(data, x => x.Test, x => x.Test2); foreach (var group in groups) { Console.WriteLine($"分组键: {string.Join(", ", group.Key.Keys)}"); foreach (var item in group) { Console.WriteLine($" 元素: Test={item.Test}, Test2={item.Test2}"); } }
运行后会得到2个分组,正好符合你的需求——相同Test和Test2组合的元素会被分到同一组。
可选优化
如果你的表达式数量是固定的,也可以用ValueTuple作为分组键,性能会更优:
// 比如固定2个表达式的情况 return source.GroupBy(item => (selector1(item), selector2(item)));
但如果表达式数量是动态传入的,用匿名类型包装列表的方式更灵活。
内容的提问来源于stack exchange,提问作者danyolgiax
相关产品推荐
相关产品推荐

