Expression trees , object comparer

c# expression-trees

Question

I need to generate expression tree than checks two objects (arguments) for equality. I know that these objects will have properties, so I have to compare their values, how to do this? So i have something like obj1, obj2 and array of strings with property names i need to check. Here's how i see this :

var leftObject = E.Parameter(typeof (object), "leftObject");
var rightObject = E.Parameter(typeof (object), "rightObject");
var properties = E.Parameter(typeof (string[]), "properties");
var i = E.Parameter(typeof(int), "i");
var equal = E.Parameter(typeof (bool), "equal");

var body = E.Block
    (
        new[] { properties, i},
        E.Assign(properties,E.Constant(props)),
        E.Assign(i,E.Constant(0)),
        E.Assign(equal,E.Constant(true)),

        E.Loop
        (
            E.Property(leftObject,props[i]) == E.Property(rightObject,props[i])
        )
    );

How to implement accessing to properties one by one in Loop?

P.S. E is my alias for Expression.

Accepted Answer

You should use reflection to discover the properties you want then basically create one big series of AndAlso expressions. e.g.

    public static Func<T, T, bool> BuildStructuralComparerDelegate<T>() where T:class
    {
        var left = Expression.Parameter(typeof(T), "left");
        var right = Expression.Parameter(typeof(T), "right");
        var referenceEquals = typeof(object).GetMethod("ReferenceEquals");
        Expression expression = Expression.AndAlso(
            Expression.Not(
                Expression.Call(
                    null,
                    referenceEquals,
                    left,
                    Expression.Default(typeof(T))
                )
            ),
            Expression.Not(
                null,
                Expression.Call(
                    referenceEquals,
                    right,
                    Expression.Default(typeof(T))
                )
            )
        );
        Array.ForEach(typeof(T).GetProperties(),property =>
            expression = Expression.AndAlso(
                expression,
                Expression.Equal(
                    Expression.Property(left, property),
                    Expression.Property(right, property)
                )
            )
        );
        var lambdaExp = Expression.Lambda<Func<T, T, bool>>(
            Expression.OrElse(
                Expression.Call(
                    null,
                    referenceEquals,
                    left,
                    right
                ),
                expression
            ),
            left,
            right
        );
        return lambdaExp.Compile();
    }

The above code only works on classes, creates an expression that is roughly

(left,right)=> object.ReferenceEquals(left,right) || (left != null && right != null && left.Property1 == right.Property1 && left.Property2 == right.Property2 && ... && left.PropertyN == right.PropertyN);

It's not a complete solution as it assumes you want to compare all properties and all your properties are Readable, but it should get you on the path. It's also .NET 3.5 compatible if you care about such things.





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why