📅  最后修改于: 2023-12-03 14:54:40.783000             🧑  作者: Mango
动态分组是一种非常常见的编程需求,它通常涉及到对一组数据进行分组,根据分组属性对数据进行聚合、排序、计数等处理。在 C# 中,我们可以使用 Linq 来实现对数据的分组。然而,Linq 提供的分组方式是静态的,需要在程序设计时确定分组属性,无法根据实际需求动态指定分组属性。本文将介绍如何使用表达式动态指定分组属性。
静态分组的代码通常是这样的:
var groups = from item in items
group item by item.Property1 into g
select new
{
Property1 = g.Key,
Count = g.Count(),
Sum = g.Sum(item => item.Property2)
};
这里通过 Linq 实现分组,Property1
是分组属性,需要在代码中静态指定,无法根据实际需求动态指定。
对于需要根据不同用户选择的属性进行分组的情况,我们可以使用下面的方式来实现动态分组。
第一种方式是根据属性名来动态指定分组属性。这种方式的实现代码如下:
public static IEnumerable<IGrouping<object, T>> DynamicGroupBy<T>(IEnumerable<T> items, string property)
{
var propExpr = GetPropertyExpression<T>(property);
return items.GroupBy(propExpr.Compile());
}
private static Expression<Func<T, object>> GetPropertyExpression<T>(string property)
{
var paramExpr = Expression.Parameter(typeof(T));
var propExpr = Expression.Property(paramExpr, property);
var convertExpr = Expression.Convert(propExpr, typeof(object));
return Expression.Lambda<Func<T, object>>(convertExpr, paramExpr);
}
函数 DynamicGroupBy
接受一个泛型序列和一个属性名,使用 GetPropertyExpression
函数获取属性的表达式,然后调用 Linq 的 GroupBy
函数进行分组。
需要注意的是,由于不同属性的类型是不同的,因此我们需要将属性的值转换为 object
类型,这可以用 Expression.Convert
函数来实现。
使用实例:
var groups = DynamicGroupBy(items, "Property1");
foreach (var group in groups)
{
Console.WriteLine(group.Key.ToString());
}
第二种方式是根据属性表达式来动态指定分组属性。这种方式的实现代码如下:
public static IEnumerable<IGrouping<object, T>> DynamicGroupBy<T, TKey>(IEnumerable<T> items, Expression<Func<T, TKey>> keySelector)
{
var convertExpr = Expression.Convert(keySelector.Body, typeof(object));
var lambdaExpr = Expression.Lambda<Func<T, object>>(convertExpr, keySelector.Parameters);
return items.GroupBy(lambdaExpr.Compile());
}
函数 DynamicGroupBy
接受一个泛型序列和一个属性表达式,使用 Expression.Convert
函数将表达式的结果转换为 object
类型,然后使用 Expression.Lambda
函数将表达式转换为 Lambda 表达式,最后调用 Linq 的 GroupBy
函数进行分组。
使用实例:
var groups = DynamicGroupBy(items, x => x.Property1);
foreach (var group in groups)
{
Console.WriteLine(group.Key.ToString());
}
本文介绍了两种按表达式动态分组的方法,它们可以根据用户选择的属性动态指定分组属性,极大地提高了程序的灵活性和可扩展性。