这里的挑战是您需要构建一个匿名类型才能拥有一个GroupBy
可以转换为 SQL 或任何其他 LINQ 提供程序的表达式。
我不确定您是否可以使用反射来做到这一点(并非没有一些非常复杂的代码来在运行时创建匿名类型)。但是,如果您愿意提供匿名类型的示例作为种子,则可以创建分组表达式。
public static Expression<Func<TSource, TAnon>> GetAnonymous<TSource,TAnon>(TSource dummy, TAnon example)
{
var ctor = typeof(TAnon).GetConstructors().First();
var paramExpr = Expression.Parameter(typeof(TSource));
return Expression.Lambda<Func<TSource, TAnon>>
(
Expression.New
(
ctor,
ctor.GetParameters().Select
(
(x, i) => Expression.Convert
(
Expression.Property(paramExpr, x.Name), // fetch same named property
x.ParameterType
)
)
), paramExpr);
}
以下是您将如何使用它(注意:传递给该方法的虚拟匿名类型是为了使匿名类型成为编译时类型,该方法不关心您为它传递的值是什么。 ) :
static void Main()
{
var groupByExpression = GetAnonymous(new Frog(), new {IsAlive = true, IsVirulent = true});
Console.WriteLine(groupByExpression);
var frogs = new []{ new Frog{ IsAlive = true, IsVirulent = false}, new Frog{ IsAlive = false, IsVirulent = true}, new Frog{ IsAlive = true, IsVirulent = true}};
var grouped = frogs.AsQueryable().GroupBy(groupByExpression);
foreach (var group in grouped)
{
Console.WriteLine(group.Key);
}
}
产生:
Param_0 => new <>f__AnonymousType0`2(Convert(Param_0.IsAlive, Boolean), Convert(Param_0.IsVirulent, Boolean))
{ IsAlive = True, IsVirulent = False }
{ IsAlive = False, IsVirulent = True }
{ IsAlive = True, IsVirulent = True }