call sum in expression tree

I have this query:

Dim test = result.GroupBy(Function(row) groupedindexes.Select(
                              Function(grpindex) row(grpindex)).ToArray, comp).
                      Select(Function(g) New groupedresult(g.Key, g.Sum(Function(x) Convert.ToInt32(x(3)))))

At the moment, I'm building this: g.Sum(Function(x) Convert.ToInt32(x(3)))

I have this so far:

Dim groupparameter = Expression.Parameter(GetType(Linq.IGrouping(Of Object(), Object())), "g")
Dim objectparameter = Expression.Parameter(GetType(Object()), "x")
convertMethod = GetType(System.Convert).GetMethod("ToInt32", New Type() {GetType(Object)})
Dim aggregator_expr As LambdaExpression = Expression.Lambda(expression.Call(convertMethod, Expression.ArrayAccess(objectparameter, Expression.Constant(3))), objectparameter)
Dim aggregator_func = GetType(Enumerable).GetMethods(BindingFlags.Public Or BindingFlags.Static).
Where(Function(m) m.Name = "Sum").Where(Function(m) m.ReturnType.FullName = "System.Int32").First
Dim aggregation As Expression = Expression.Call(aggregator_func, groupparameter, aggregator_expr)

At the last row, vs says:

Incorrect number of arguments supplied for call to method 'Int32 Sum(System.Collections.Generic.IEnumerable`1[System.Int32])'

Sure, there is one parameter more. But if I remove the groupparameter, I get another error message. How can I correct this?

Thanks.

EDIT:

here a simple console application:

Imports System.Reflection
Imports System.Linq.Expressions
Module Module1
    Dim groupparameter = Expression.Parameter(GetType(Linq.IGrouping(Of Object(), Object())), "g")
    Dim objectparameter = Expression.Parameter(GetType(Object()), "x")
    Dim convertMethod = GetType(System.Convert).GetMethod("ToInt32", New Type() {GetType(Object)})
    Dim aggregator_expr As LambdaExpression = Expression.Lambda(
        Expression.Call(convertMethod, Expression.ArrayAccess(objectparameter, Expression.Constant(3))), objectparameter)
    Dim aggregator_func = GetType(Enumerable).GetMethods(BindingFlags.Public Or BindingFlags.Static).
    Where(Function(m) m.Name = "Sum").Where(Function(m) m.ReturnType.FullName = "System.Int32" AndAlso m.GetParameters.Length = 2)(0).
    MakeGenericMethod(GetType(System.Func(Of Object(), Integer)))
    Sub Main()
        Dim aggregation As Expression = Expression.Call(Nothing, aggregator_func, aggregator_expr, groupparameter)
    End Sub
End Module

As you see, I changed a bit the aggregator_func. I would like to call this expression: g.Sum(Function(x) Convert.ToInt32(x(3))).

I have all together, I need only to call the variables in the right order. But I don't get it.

EDIT: The code can simply copy&paste in vs to see, what is wrong.

Jon Skeet
people
quotationmark

Firstly, you're looking in Enumerable for methods - that's not a good idea if you're trying to work with expression trees. You should be looking in Queryable.

Next, you need to understand that the Sum method is overloaded - and there are multiple methods which return Int32. You need to check whether the method has two parameters. Note that you can check for multiple conditions in a single Where. For example:

Where(Function(m) m.Name = "Sum" AndAlso
                  m.ReturnType = GetType(Integer) AndAlso
                  m.GetParameters().Length = 2)

Hopefully that should at least find you the right method to call. I can't easily tell whether that's all that's wrong (a short but complete program demonstrating what you're trying to do would help) but it should at least get you closer.

EDIT: The parameters you're using are all over the place. For example, you've got an IGrouping<object[], object[]> - that isn't an IEnumerable<Func<object[], int>> - it's an IEnumerable<object[]>. And you're currently specifying the arguments in the wrong order too - the target of an extension method is the first parameter. So here's a short but complete program that doesn't throw an exception:

Imports System.Reflection
Imports System.Linq.Expressions

Class Test
    Shared Sub Main()
        Dim groupParameter = Expression.Parameter(GetType(Linq.IGrouping(Of Object(), Object())), "g")
        Dim objectParameter = Expression.Parameter(GetType(Object()), "x")
        Dim convertMethod = GetType(System.Convert).GetMethod("ToInt32", New Type() {GetType(Object)})

        Dim aggregatorExpr As LambdaExpression = Expression.Lambda(
            Expression.Call(
                convertMethod,
                Expression.ArrayAccess(objectParameter, Expression.Constant(3))
            ), objectParameter)
        Dim aggregatorFunc = GetType(Enumerable) _
            .GetMethods(BindingFlags.Public Or BindingFlags.Static) _
            .Where(Function(m) m.Name = "Sum") _
            .Where(Function(m) m.ReturnType.FullName = "System.Int32") _
            .Where(Function(m) m.GetParameters.Length = 2)(0) _
            .MakeGenericMethod(GetType(Object()))
        Dim aggregation As Expression = Expression.Call(
            Nothing,
            aggregatorFunc,
            groupParameter,
            aggregatorExpr)
    End Sub
End Class

people

See more on this question at Stackoverflow