У меня есть коллекция, которая IEnumerable<Transaction>
.Транзакция имеет несколько свойств, таких как TransactionId (Int64), PaymentMethod (строка) и TransactionDate (DateTime)
Я хотел бы иметь возможность выполнить это transactions.GroupBy(x => x.PaymentMethod)
динамически во время выполнения на основе любого поля группировки пользователярешил использовать.
Я нашел большую часть ответа, который я ищу, в ответе dtb здесь Linq GroupBy - как указать ключ группировки во время выполнения?
Это хорошо работает:
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 );
За исключением того, что я не знаю тип возвращаемого типа Func в Expression.Lambda<Func<Transaction, string>>
.В этом примере это строка, но это может быть Int64, десятичное число, DateTime и т. Д. Я не могу использовать Object в качестве возвращаемого типа, потому что у меня могут быть типы значений.и большинство из них, кажется, применимы к IQueryable и LinqToSQL.
Использование класса Expression кажется хорошим способом сделать это, но есть ли способ сделать это, когда я не знаю ни имени, ни типа данных параметра моей группы во время компиляции?
Я ценю любое движение в правильном направлении.
Редактировать:
Используя решение Polity ниже, я создал метод расширения, который делает то, что я пытался сделать:
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 и всем, кто ответил!