Reputation: 108
I am trying to create an expression for one list property, but facing an error as below.
Error: Incorrect number of arguments supplied for call to method Sum
I tried bellow code
ParameterExpression argParam = Expression.Parameter(typeof(T), "s");
property1 = typeof(T).GetProperty(nameof(Srt));
property2 = property1.PropertyType.GetProperty(Srt.Srtd));
propertyExp1 = Expression.Property(argParam, property1);
propertyExp = Expression.Property(propertyExp1, property2);
// in propertyExp I got {s.Srt.Srtd}
ParameterExpression argX = Expression.Parameter(typeof(Srtd), "x");
var prt1= typeof(Srtd).GetProperty(nameof(Srtd.Elt));
var prtExp= Expression.Property(argX, prt1);
// in prtExp I got {x.Elt}
var method = typeof(System.Linq.Enumerable).GetMethod("Sum", new[] { typeof(IEnumerable<decimal?>) });
var exp2 = Expression.Call(method, propertyExp, prtExp);
In Expression.Call I am facing the error "Incorrect number of arguments supplied for call to method Sum".
I want expression like { s.Srt.Srtd.Sum(x=>x.Elt) }, Can someone help me for this?
Upvotes: 0
Views: 326
Reputation: 112324
Note that Sum
in s.Srt.Srtd.Sum(x=>x.Elt)
is an extension method having a hidden first this
parameter and a second selector parameter:
public static decimal? Sum<TSource> (
this System.Collections.Generic.IEnumerable<TSource> source,
Func<TSource,decimal?> selector);
Therefore, we would have to provide two type arguments:
method = typeof(System.Linq.Enumerable)
.GetMethod("Sum", new[] {
typeof(IEnumerable<Srtd>),
typeof(Func<Srtd,decimal?>)
});
However, the problem here is that the TSource
type parameter of the method as it is declared in Enumerable
is open. It is possible to write typeof(IEnumerable<>)
, but not typeof(Func<,decimal?>)
for the selector with only one of the two parameters open.
Instead, I will be using GetMethods()
and filter the right method in a LINQ query in the example below. What remains to do is to specify the open generic type parameter with MakeGenericMethod
.
I used this setup (as specified in one of your comments, but made the decimal nullable as in your question):
class T { public A a { get; set; } }
class A { public List<B> b { get; set; } }
class B { public decimal? c { get; set; } }
Note that you have to make a Lambda expression for x => x.c
. I don't see this in your attempt.
// Parameter t in: t => t.a.b.Sum(x => x.c)
ParameterExpression paramT = Expression.Parameter(typeof(T), "t");
// Property a in: t.a
PropertyInfo propTa = typeof(T).GetProperty(nameof(T.a));
// Property b in: a.b
PropertyInfo propAb = typeof(A).GetProperty(nameof(A.b));
// Expression: t.a
MemberExpression taExpr = Expression.Property(paramT, propTa);
// Expression: t.a.b
MemberExpression tabExpr = Expression.Property(taExpr, propAb);
// Parameter x in: x => x.c
ParameterExpression paramX = Expression.Parameter(typeof(B), "x");
// Property c in: x.c where x is of type B
PropertyInfo propBc = typeof(B).GetProperty(nameof(B.c));
// Expression: x.c
MemberExpression xcExpr = Expression.Property(paramX, propBc);
// Method: public static decimal? Sum<B>(this IEnumerable<B> source, Func<B, decimal?> selector)
MethodInfo sumMethod = typeof(System.Linq.Enumerable).GetMethods()
.Where(m => m.Name == "Sum" &&
m.ReturnType == typeof(decimal?) &&
m.GetParameters().Length == 2)
.First()
.MakeGenericMethod(typeof(B));
// Lambda expression: x => x.c
LambdaExpression lambdaXToXc = Expression.Lambda(xcExpr, paramX);
// Call expression: t.a.b.Sum(x => x.c). Instance is null because method is static
MethodCallExpression sumCallExpr = Expression.Call(instance: null, method: sumMethod, tabExpr, lambdaXToXc);
Upvotes: 2