【问题标题】:ArgumentException when calling Expression.GreaterThanOrEqual via Expression.Call通过 Expression.Call 调用 Expression.GreaterThanOrEqual 时出现 ArgumentException
【发布时间】:2017-05-17 10:08:08
【问题描述】:

我在动态或直接调用Expression.GreaterThanOrEqual 时会出现不同的行为。

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace ExpressionExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Build expression head.
            ParameterExpression param = Expression.Parameter(typeof(MyObj), "x");
            MemberExpression property = Expression.Property(param, "MyProperty");

            int value = 1;

            // Build expression body.
            MethodInfo greaterThanOrEqual = typeof(Expression)
                .GetMethod("GreaterThanOrEqual",
                    new[] { typeof(Expression), typeof(Expression) });

            Expression valueExpr = Expression.Convert(Expression.Constant(value),
                property.Type);

            // Dynamic Call
            //var expressionBody = Expression.Call(null, greaterThanOrEqual, property,
                  valueExpr);
            // Direct Call
            var expressionBody = Expression.GreaterThanOrEqual(property, valueExpr);

            // Make Lambda.
            Expression.Lambda<Func<MyObj, bool>>(expressionBody, param);
        }
    }

    class MyObj
    {
        public int MyProperty { get; set; }
    }
}

为了简单起见,我将代码断章取义。最后的 Lambda 稍后在 Queryable 的 where 方法中使用。直接调用工作正常并给出了预期的结果。然而,动态调用会引发System.ArgumentException,表示System.Int32 不能用作BinaryExpression GreaterThanOrEqual 的参数。这实际上是我之前转换值的原因,这也是直接调用所必需的。

这里有什么不同?我怎样才能让动态调用起作用?

【问题讨论】:

  • 不同的是,你所说的动态调用根本不是调用。为了为您提供解决方案,您需要提供需要动态调用的示例用例。
  • 我用一个最小且可运行的例子更新了这个问题。
  • 好的,但这不是我需要的。我知道它是可重现的,但找不到动态调用的实际需求(用例)来回答您的第二个问题(如何使其工作)。
  • 我正在开发一个由 json 控制的过滤器(表达式树)。因此,您向 API 发送请求以获取实体列表。响应包含的实体由 (json) 过滤器确定。过滤器是一个包含布尔代数的树形式的公式。目前,等式表达式被分离成它们自己的方法。现在我想称他们只有 MethodInfo。

标签: c# entity-framework reflection lambda expression-trees


【解决方案1】:

我仍然不了解您的请求的实际用途(因此需要),所以只是回答您的具体问题。

这里有什么区别?

不同之处在于Expression.Call 并不真正调用该方法,而是创建一个MethodCallExpression,它表示对表达式树内的方法的调用。因此,它不应该用于调用其他 Expression 构建器方法。

我怎样才能让动态调用起作用?

您需要简单地通过反射调用methof,而不是Expression.Call

// Dynamic Call
var expressionBody = (Expression)greaterThanOrEqual.Invoke(
    null, new object[] { property, valueExpr });

【讨论】:

    猜你喜欢
    • 2016-12-09
    • 1970-01-01
    • 2014-04-16
    • 2014-10-27
    • 1970-01-01
    • 2014-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多