0

I have built an expression tree which seems to result in an expression of type Expression<Func<object, bool>> and a return type bool which I think is what I want. But when I try to compile it into a Func<object, bool> I am getting the following System.ArgumentException:

"Expression of type 'System.Func`2[System.Object,System.Boolean]' cannot be used for return type 'System.Boolean"

My end goal is to create a return a function I can use on different objects where I know the property name and test if the property satisfies a certain condition. I don't understand why the final step is failing because from the exception it seems like I do have the anticipated Expression<Func<object, bool>> and I would think it can be used with return type bool. Here is the code:

public delegate Expression ComparisonExpressionDelegate(Expression property, Expression value);
public class ConditionCompiler
{
    public class TestClass
    {
        public string StringProperty1 { get; set; }
        public string StringProperty2 { get; set; }
        public string StringProperty3 { get; set; }
        public int IntProperty1 { get; set; }
        public double DoubleProperty1 { get; set; }
    }
    public static Func<object, bool> Test() //This is called
    {
        PropertyInfo property = typeof(TestClass).GetProperty(nameof(TestClass.StringProperty1));
        object value = "1";
        return CompileExpression(property, value);
    }
    public static Func<object, bool> CompileExpression(PropertyInfo property, object value)
    {
        ParameterExpression obj = Expression.Parameter(typeof(object), "obj");
        Expression resultExpression = CreateExpression(property, value);
        Func<object, bool> resultLambda
            = Expression.Lambda<Func<object, bool>>(resultExpression, obj).Compile(); //Issue is here
        return resultLambda;
    }

    public static Expression CreateExpression(PropertyInfo property, object value)
    {
        ParameterExpression obj = Expression.Parameter(typeof(object), "obj");
        bool isGetMethodStatic = property.GetGetMethod().IsStatic;
        UnaryExpression typedTarget = Expression.Convert(obj, property.DeclaringType);
        MemberExpression memberAccess = Expression.Property(isGetMethodStatic ? null : typedTarget, property);
        UnaryExpression boxedGetter = Expression.TypeAs(memberAccess, typeof(object));
        ConstantExpression valueExpression = Expression.Constant(value);
        ComparisonExpressionDelegate comparisonExpressionDelegate = ToString_Equals_ToString_Expression;
        Expression conditionExpression = comparisonExpressionDelegate(boxedGetter, valueExpression);
        LambdaExpression conditionExpressionLambda = Expression.Lambda(conditionExpression, obj);
        return conditionExpressionLambda;
    }
    private static ComparisonExpressionDelegate ToString_Equals_ToString_Expression
        = (property, value) => Expression.Equal(
            Expression.Call(
                typeof(string),
                nameof(String.Compare),
                null,
                Expression.Call(property, "ToString", null),
                value, Expression.Constant(StringComparison.OrdinalIgnoreCase)
                ),
            Expression.Constant(0)
            );
}
Michael Wagner
  • 314
  • 1
  • 12
  • You need to actually invoke/evaluate the expression to get a `bool` value. See duplicate. – Peter Duniho Jul 22 '21 at 00:07
  • Your code boils down to `Expression.Lambda(Expression.Lambda(...))` which is not what you want `CompileExpression` to do. Just compile the result of `CreateExpression` (and perhaps change the return type), don't try to wrap it in another lambda. – Jeremy Lakeman Jul 22 '21 at 00:53

0 Answers0