📜  按表达式动态分组 C# (1)

📅  最后修改于: 2023-12-03 14:54:40.783000             🧑  作者: Mango

按表达式动态分组 C#

动态分组是一种非常常见的编程需求,它通常涉及到对一组数据进行分组,根据分组属性对数据进行聚合、排序、计数等处理。在 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());
}
总结

本文介绍了两种按表达式动态分组的方法,它们可以根据用户选择的属性动态指定分组属性,极大地提高了程序的灵活性和可扩展性。