Search code examples
c#linqlambdaexpression-trees

ParameterExpression of type 'MyClass' cannot be used for delegate parameter of type 'System.Object'


I've built an expression tree of type Func<object,bool>. But when I try to compile it I get exception:

ParameterExpression of type 'MyClass' cannot be used for delegate parameter of type 'System.Object'

The type of the calling object is unknown until run-time.

Expression leftFunc, rightFunc;
var x = Expression.Parameter(t);
if (left_element.All(char.IsDigit)) 
    leftFunc = Expression.Constant(int.Parse(left_element));
else 
    leftFunc = Expression.PropertyOrField(x, left_element);
if (right_element.All(char.IsDigit)) 
    rightFunc = Expression.Constant(int.Parse(right_element));
else 
    rightFunc = Expression.PropertyOrField(x, right_element);
var result = Expression.Lambda<Func<object, bool>>(
        Expression.GreaterThan(leftFunc, rightFunc), x); //exception thrown on this line
return result;

x is of type MyClass, could I use a converter in some way?


Solution

  • Update after reading comment.

    Full code, working:

    void Main()
    {
        var method = something(typeof(MyClass), "propA", "propB");
        var classes = new List<MyClass>();
        classes.Add(new MyClass { propA = 1, propB = 2 }); // Should return false
        classes.Add(new MyClass { propA = 3, propB = 2 }); // Should return true
        classes.Add(new MyClass { propA = 2, propB = 2 }); // Should return false
        var res = classes.Where(method);
        res.Dump(); //Only class with propA = 3 && propB == 2 is returned
    }
    
    private Func<object, bool> something(Type t, string left_element, string right_element)
    {
        var props = t.GetProperties();
        return (onObject) => {
            int left_int;
            object leftSide;
            if (!int.TryParse(left_element, out left_int))
            {
                leftSide = props.FirstOrDefault (p => p.Name == left_element).GetValue(onObject);
            } else {
                leftSide = left_int;
            }
    
            int right_int;
            object rightSide;
            if (!int.TryParse(right_element, out right_int))
            {
                rightSide = props.FirstOrDefault (p => p.Name == right_element).GetValue(onObject);
            } else {
                rightSide = left_int;
            }
    
            return Comparer.Default.Compare(leftSide, rightSide) > 0;       
        };
    }
    
    private class MyClass {
        public int propA {get;set;}
        public int propB {get;set;}
    }