通过表达式调用可枚举平均值

时间:2014-08-25 08:44:34

标签: c# linq expression expression-trees

我正在尝试编写动态代码来执行一些聚合,包括Average,Sum,Max等。

这是我正在执行的代码:

PropertyInfo sortProperty = typeof(T).GetProperty("PropertyName");

ParameterExpression parameter = Expression.Parameter(typeof(T), "p");


MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, sortProperty);
LambdaExpression orderByExp = Expression.Lambda(propertyAccess, parameter);

var exp = Expression.Lambda<Func<T, int>>(propertyAccess, parameter);

var call = Expression.Call(typeof(Enumerable), "Average", new[] { typeof(IEnumerable<T>) , typeof(Func<T, int>) }, parameter);

我总是得到那个例外:

  

类型'System.Linq.Enumerable'上没有泛型方法'Average'与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。

1 个答案:

答案 0 :(得分:3)

让我们来看看这一行。在这里,您正在呼叫Call

var call = Expression.Call(typeof(Enumerable), "Average", new[] { typeof(IEnumerable<T>) , typeof(Func<T, int>) }, parameter);

第三个参数是“Type对象的数组,用于指定泛型方法的类型参数。”。您传递的是IEnumerable<T>Func<T, int>类型,但是Average takes only a single type parameter (TSource)

第四个参数是“Expression对象的数组,表示方法的参数。”。您传递的表达式代表T,但Average需要IEnumerable<TSource>Func<TSource, decimal>(或者您要调用的任何重载,我只会使用{ {1}}一个例子)。

我不知道您的最终目标是使用此代码,但它可能应该如下所示:

decimal

这是使用此代码的一个小例子(你会明白的):

PropertyInfo sortProperty = typeof(T).GetProperty("Prop");
ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, sortProperty);

// parameter for the source collection
ParameterExpression source = Expression.Parameter(typeof(IEnumerable<T>), "source");

var exp = Expression.Lambda<Func<T, decimal>>(propertyAccess, parameter);
var call = Expression.Call(typeof(Enumerable), "Average", new[] {typeof(T)}, source, exp);