Linq - Dynamic GroupBy with IEnumerable< T> [英] Linq - Dynamic GroupBy with IEnumerable<T>

查看:151
本文介绍了Linq - Dynamic GroupBy with IEnumerable< T>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 IEnumerable< Transaction> 的集合。事务有几个属性,如TransactionId(Int64),PaymentMethod(string)和TransactionDate(DateTime)

I have a collection that is IEnumerable<Transaction>. Transaction has several properties such as TransactionId (Int64), PaymentMethod(string) and TransactionDate(DateTime)

我想要能够完成这个 transaction.GroupBy(x => x.PaymentMethod)在运行时动态地基于用户决定使用的任何分组字段。

I'd like to be able to accomplish this transactions.GroupBy(x => x.PaymentMethod) dynamically at run time based on whatever grouping field the user has decided to use.

我在dtb的答案中找到了我正在寻找的大部分答案 Linq GroupBy - 如何在运行时指定分组密钥?

I found most of the answer I'm looking for in dtb's answer here Linq GroupBy - how to specify the grouping key at runtime?

这样做很好:

        var arg = Expression.Parameter( typeof( Transaction ), "transaction" );
        var body = Expression.Property( arg, "PaymentMethod" );
        var lambda = Expression.Lambda<Func<Transaction, string>>( body, arg );
        var keySelector = lambda.Compile();

        var groups = transactions.GroupBy( keySelector );

除了我不知道在<$ c $中的Func的返回类型的类型c> Expression.Lambda 。这是这个例子中的字符串,但它可能是Int64,decimal,DateTime等。我不能使用Object作为返回类型,因为我可能有值类型。

Except that I don't know the type of the return type of the Func in Expression.Lambda<Func<Transaction, string>>. It's string in this example, but it might be Int64, decimal, DateTime, etc. I can't use Object as the return type because I might have value types.

我一直在阅读很多SO帖子,其中大多数似乎适用于IQueryable和LinqToSQL。

I've been reading lots of SO posts and most of them seem to apply to IQueryable and LinqToSQL.

使用Expression类似乎是一个很好的方式来完成此操作,但是当我不知道我的组的名称或数据类型时,是否有一种方法参数在编译时?

Using the Expression class seems like a good way to accomplish this, but is there a way to do it when I don't know either the name or datatype of my group parameter at compile time?

感谢任何微调正确的方向。

I appreciate any nudge in the right direction.

编辑:

使用下面的Polity解决方案,我创建了一个扩展方法,它做了我一直在努力做的:

Using Polity's solution below, I created an extension method that does what I've been trying to do:

    public static IEnumerable<IGrouping<object, T>> GroupBy<T>( this IEnumerable<T> items, string groupByProperty )
    {

        var arg = Expression.Parameter( typeof(T), "item" );
        var body = Expression.Convert( Expression.Property( arg, groupByProperty ), typeof( object ) );
        var lambda = Expression.Lambda<Func<T, object>>( body, arg );
        var keySelector = lambda.Compile();

        var groups = items.GroupBy( keySelector );
        return groups;
    } 

感谢Polity和所有回答的人!

Thanks to Polity and everyone who answered!

推荐答案

关于ojlovecd的答案。

Following up on the answer of ojlovecd.

根据一个人要求他在运行时需要功能。泛型和运行时不是最简单的组合。这是没有问题的,因为你可以只是将返回值作为一个对象来威胁,它使ojlovecd提供的方法的非泛型变体类似于:

According to the one asking he needs functionality at runtime. Generics and Runtime arent the easiest mix. That is no problem though since you can just threat the return value as an object which makes the non-generic variant of the method provided by ojlovecd something like:

static IEnumerable<IGrouping<object,Transaction>> GroupBy(string propName) 
{ 
    List<Transaction> transactions = new List<Transaction>  
    { 
        new Transaction{ PaymentMethod="AA", SomeDateTime=DateTime.Now.AddDays(-1), SomeDecimal=1.2M, SomeInt64=1000}, 
        new Transaction{ PaymentMethod="BB", SomeDateTime=DateTime.Now.AddDays(-2), SomeDecimal=3.4M, SomeInt64=2000}, 
        new Transaction{ PaymentMethod="AA", SomeDateTime=DateTime.Now.AddDays(-1), SomeDecimal=3.4M, SomeInt64=3000}, 
        new Transaction{ PaymentMethod="CC", SomeDateTime=DateTime.Now.AddDays(2), SomeDecimal=5.6M, SomeInt64=1000}, 
    }; 
    var arg = Expression.Parameter(typeof(Transaction), "transaction"); 
    var body = Expression.Convert(Expression.Property(arg, propName), typeof(object)); 
    var lambda = Expression.Lambda<Func<Transaction, object>>(body, arg); 
    var keySelector = lambda.Compile(); 

    var groups = transactions.GroupBy(keySelector); 
    return groups; 
} 

这篇关于Linq - Dynamic GroupBy with IEnumerable&lt; T&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆