mercredi 21 juillet 2021

How do I convert a Linq expression to a Func<> to use?

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




Aucun commentaire:

Enregistrer un commentaire