I'm trying to write dynamic code that do some aggregations Average, Sum, Max, etc.
That's the code im executing :
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);
and I always get that exception:
No generic method 'Average' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
Let's look at this line. Here you're calling Call
var call = Expression.Call(typeof(Enumerable), "Average", new[] { typeof(IEnumerable<T>) , typeof(Func<T, int>) }, parameter);
The third parameter is "An array of Type objects that specify the type parameters of the generic method.". You're passing the types IEnumerable<T>
and Func<T, int>
, but Average
takes only a single type parameter (TSource
).
The forth parameter is "An array of Expression objects that represent the arguments to the method.". You're passing an expression representing a T
, but Average
expects an IEnumerable<TSource>
and a Func<TSource, decimal>
(or whatever overload you want to call, I'll just use the decimal
one as an example).
I don't know what your final goal is using this code, but it probably should look like:
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);
Here's a small example using this code (you'll get the idea):
// assuming a class called T with a decimal property called Prop
// because I'm a lazy and terrible person
var method = Expression.Lambda<Func<IEnumerable<T>, decimal>>(call, source).Compile();
var result = method(new List<T> {new T { Prop=10}, new T { Prop=20}});
// result is now 15