views:

600

answers:

3

Is it possible to find out if two expressions are the same?

Like given the following four expressions:

        Expression<Func<int, bool>> a = x => false;
        Expression<Func<int, bool>> b = x => false;
        Expression<Func<int, bool>> c = x => true;
        Expression<Func<int, bool>> d = x => x == 5;

Then, at least as we can see that:

  • a == b
  • a != c
  • a != d

But can I do anything to find this out in my code?

Took a peek in the msdn library, where it says that

Equals: Determines whether the specified Object is equal to the current Object. (Inherited from Object.)

which I guess means that at least the Expression class hasn't overrided the equals method to become Equatable? So how would you do this? Or am I asking too much here? :p

+2  A: 

It strikes me that this might be difficult to do, except in the simplest of cases.

For example:

var numbers1 = Enumerable.Range(1, 20);
Expression<Func<int, IEnumerable<int>>> a = x => numbers1;
var numbers2 = Enumerable.Range(1, 20);
Expression<Func<int, IEnumerable<int>>> b = x => numbers2;

Technically, these are equal, but how could it be determined without evaluating the IEnuemrable returned in each expression?

Dustin Campbell
I'm asking you guys here :p hehe. But yes, I can see the problem.. but I can also.. not see it. Cause like you said, technically those are in fact equal. And, at least I, would think that one expression tree should be comparable to another expression tree based on their nodes and data types.
Svish
In your example I think I might have considered those expressions unequal though, since they contain a reference to an object which are not the same...
Svish
numbers1 or numbers2 will be serialized as a ConstantExpression node, whose values won't be equal.
Jb Evain
@Jb: are Expressions serializeable?
Svish
Nope, they're not.
Jb Evain
But there is hope. In this post I explain how to serialize linq expressions - http://www.shunra.com/shunrablog/index.php/2009/07/16/using-linq-expressions-in-a-client-server-application/
mark
+7  A: 

You can have a look at the type ExpressionEqualityComparer that is used inside Linq to db4o. It implements the interface IEqualityComparer<T>, so it's usable for generic collections, as well as for a standalone usage.

It uses the type ExpressionComparison to compare two Expressions for equality, and HashCodeCalculation, to compute a hashcode from an Expression.

It all involves visiting the expression tree, so it can be pretty costly if you do it repeatedly, but it can also be quite handy.

The code is available under the GPL or the dOCL

For instance, here's your test:

using System;
using System.Linq.Expressions;

using Db4objects.Db4o.Linq.Expressions;

class Test {

    static void Main ()
    {
     Expression<Func<int, bool>> a = x => false;
     Expression<Func<int, bool>> b = x => false;
     Expression<Func<int, bool>> c = x => true;
     Expression<Func<int, bool>> d = x => x == 5;

     Func<Expression, Expression, bool> eq =
      ExpressionEqualityComparer.Instance.Equals;

     Console.WriteLine (eq (a, b));
     Console.WriteLine (eq (a, c));
     Console.WriteLine (eq (a, d));
    }
}

And it indeed prints True, False, False.

Jb Evain
Did look promising, but what are these ExpressionComparison(a, b).AreEqual and HashCodeCalculation(expression).HashCode?
Svish
You can browse the implementation, they're in the same folder.
Jb Evain
I think I'll just try to find another way to solve what I am trying to figure out :p But your answer seems to provide a working solution, so I'll mark it as Accepted =)
Svish
A: 

As a lazy answer, you can check ToString() - it should at least indicate where they are clearly different (although it will include the var-name in there, so that would have to be the same).

For checking equivalence accurately... much harder - a lot of work, over a lot of different node types.

Marc Gravell
Lol, now that may actually kind of work... :D
Svish
No, not every expression has a usable string representation. Convert for instance doesn't indicate which types it converts to.
Jb Evain
Exactly - I said it would find obviously wrong answers, but that is about it. You'd need to walk the tree properly, checking the actual operators used, etc, to do a thorough job.
Marc Gravell