Search code examples
c#entity-frameworkreflectionlambdaexpression-trees

ArgumentException when calling Expression.GreaterThanOrEqual via Expression.Call


I get different behaviours when calling Expression.GreaterThanOrEqual dynamically or directly.

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; }
    }
}

I took the code out of context for simplicity reasons. The Lambda at the end is later used within a where method of a Queryable. The direct call works fine and gives expected results. The dynamic call however throws a System.ArgumentException saying that System.Int32cannot be used as a parameter for the BinaryExpression GreaterThanOrEqual. That's actually the reason why I convert the value previously, which is also necessary for the direct call.

What's the difference here? How could I get the dynamic call to work?


Solution

  • I still don't understand the practical usage (hence the need) of your request, so just answering your concrete questions.

    Whats the difference here?

    The difference is that Expression.Call does not really call the method, but creates a MethodCallExpression which represents a call to method inside the expression tree. Thus it's not supposed to be used to invoke other Expression builder methods.

    How could I get the dynamic call to work?

    Instead of Expression.Call, you need to simply invoke the methof via reflection:

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