【问题标题】:call sum in expression tree在表达式树中调用 sum
【发布时间】:2015-01-29 20:31:43
【问题描述】:

我有这个问题:

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)))))

目前,我正在构建这个:g.Sum(Function(x) Convert.ToInt32(x(3)))

到目前为止我有这个:

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)

在最后一行,vs 说:

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

当然,还有一个参数。但是,如果我删除 groupparameter,我会收到另一条错误消息。我该如何纠正这个问题?

谢谢。

编辑:

这里是一个简单的控制台应用程序:

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

如你所见,我对aggregator_func 做了一些改动。我想调用这个表达式:g.Sum(Function(x) Convert.ToInt32(x(3)))

我都在一起了,我只需要以正确的顺序调用变量。但我不明白。

编辑:代码可以简单的复制粘贴到vs中看看,有什么问题。

【问题讨论】:

  • 其他错误信息是什么?

标签: vb.net linq sum expression-trees


【解决方案1】:

首先,您在 Enumerable 中查找方法 - 如果您尝试使用表达式树,这不是一个好主意。您应该查看Queryable

接下来,您需要了解Sum 方法被重载 - 并且有多个方法返回Int32。您需要检查该方法是否有两个参数。请注意,您可以在单个 Where 中检查多个条件。例如:

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

希望这至少应该为您找到正确的调用方法。我不能轻易判断这是否是错误的全部(一个简短但完整的程序展示你正在尝试做的事情会有所帮助)但它至少应该让你更接近。

编辑:您使用的参数无处不在。例如,您有一个IGrouping<object[], object[]> - 这不是IEnumerable<Func<object[], int>> - 它是一个IEnumerable<object[]>。而且您当前也以错误的顺序指定参数 - 扩展方法的目标是 first 参数。所以这是一个简短但完整的程序,不会抛出异常:

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

【讨论】:

  • @derstauner:结果如何? (不清楚为什么将它们全部作为字段,而不是 Main 中的局部变量,请注意...)
  • 结果是一条错误消息:'System.Func2[System.Object[],System.Int32]' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable1[System.Func2[System.Object[],System.Int32]]' of method 'Int32 Sum[Func2](System.Collections.Generic.IEnumerable1[System.Func2[System.对象[],System.Int32]], System.Func2[System.Func2[System.Object[],System.Int32],System.Int32])'。正如我所说,我真的不知道,我应该如何在这个变量上使用 Expression.Call。天气字段或位置。变量,现在这无关紧要。我只想提供一个样本。
  • @derstauner:我已经用一个不会引发异常的类似程序编辑了我的答案。我认为您可能应该从更简单的事情开始 - 我认为您对泛型类型参数和参数顺序感到困惑。
  • 我想,我现在明白了,参数的顺序是如何工作的:假设我使用参数调用 g 上的 Sum。谢谢。
  • @derstauner:不,您确实将g 和选择器函数作为参数传递-Sum 是一种扩展方法。这就是为什么调用的第一个参数是Nothing - 它是一个静态方法,所以它不会被称为“on”任何东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-05
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-19
相关资源
最近更新 更多