通过Expression.Call调用Expression.GreaterThanOrEqual时出现ArgumentException

时间:2017-05-17 10:08:08

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

动态或直接调用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.ArgumentExceptionSystem.Int32不能用作BinaryExpression GreaterThanOrEqual的参数。这实际上是我之前转换该值的原因,这也是直接调用所必需的。

这里的区别是什么?我怎么能让动态调用工作?

1 个答案:

答案 0 :(得分:3)

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

  

这里的区别是什么?

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

  

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

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

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