Linq GroupBy - 如何在运行时指定分组键?

3

有没有一种好的方法可以使用Linq GroupBy,其中分组键是在运行时确定的?例如:我希望分组键是由用户选择的字段列表构建的 - 你能做到吗?我知道如果将所有内容转换为字符串表格,那么很容易做到这一点,但我想知道是否还有其他优雅或巧妙的方法来实现这一点。

class Item
{
    public int A, B;
    public DateTime D;
    public double X, Y, Z;
}

我有一个名为dataList<Item>。我想做的事情是,按照A分组检索X的总和,或按AB分组检索XYZ的总和。但是应该能够以某种方式在运行时指定分组所需的字段。

2个回答

8
你只需要在运行时构建一个 Func<Item, TKey> 即可:
var arg = Expression.Parameter(typeof(Item), "item");
var body = Expression.Property(arg, "D");
var lambda = Expression.Lambda<Func<Item, DateTime>>(body, arg);
var keySelector = lambda.Compile();

使用方法:

var result = source.GroupBy(keySelector);

如果你在编译时不知道属性的类型,那么它会稍微(但不太)变得更加困难。


1
我试图做那件事,但无法弄清语法,感谢提供的示例。 - toasteroven
这对我很有帮助 - 谢谢。如果在编译时不知道 Func<> 的返回类型,您有哪些选项? - Nathan Ratcliff
@NathanRatcliff 你已经知道这个问题的答案了吗? - Disappointed

5
获取Dynamic LINQ代码,并使用它的扩展功能,可以通过字符串指定keySelector。
var query = db.Foo.GroupBy( "{0}", "GroupedProperty", groupKey );

如果您希望按键分组返回整个对象,您可能还需要考虑添加自己的扩展。

public static IQueryable GroupByComplete( this IQueryable source, string keySelector, params object[] values )
{
    if (source == null) throw new ArgumentNullException( "source" );
    if (keySelector == null) throw new ArgumentNullException( "keySelector" );
    LambdaExpression keyLambda = DynamicExpression.ParseLambda( source.ElementType, null, keySelector, values );
    return source.Provider.CreateQuery(
        Expression.Call(
            typeof( Queryable ), "GroupBy",
            new Type[] { source.ElementType, keyLambda.Body.Type },
            source.Expression, Expression.Quote( keyLambda ) ) );
}

看起来就是我想要的。看了源代码,我猜它比我想象的更复杂,好在我没有浪费太多时间试着自己写 :) - toasteroven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接