none
Comparing delegates for equality RRS feed

  • Question

  • Hi All,

    Does anybody know of an effective/proper method to compare delegates for equality? I basically have two problems.

    1 Delegates that logically should be the same are different when compared. Like:

    If I create a lambda expression the produces a lambda independent of any external parameters and compile it then the results of that compiled lambda are always different

    Expression<Func<Func<int,int>>> exp = () => x => x + 10 ;
    Func<Func<int,int>> compiled = exp.Compile();
    bool res = object.Equals( compiled(), compiled() ); // res is always false.

    2 More worying is that the hash of a delegate seems to only depend on the delegate signature:

    Func<int,int> f1 = x => x + 1;
    Func<int,int> f2 = x => x + 2;
    bool res = f1.GetHashCode() == f2.GetHashCode(); //res is always true.

    I am trying to build a cache of objects where a lamba is part of the key. The above problems cause it to have a very bad performance.

    Tx,

    Thomas.
    Wednesday, November 26, 2008 10:44 AM

Answers

  • Disclamer I have no clue of inside knowledge to back up that this is actually a good idea or won't break in some edge cases but when you compare the method of the dynamically generated method it seems to do what you want (atleast for the two examles you gave):

    1. Expression<Func<Func<int,int>>> exp = () => x => x + 10 ;
    Func<Func<int,int>> compiled = exp.Compile();
    bool res = object.Equals( compiled().Method, compiled().Method );

    2. Func<int,int> f1 = x => x + 1;
    Func<int,int> f2 = x => x + 2;
    bool res = f1.Method.GetHashCode() == f2.Metod.GetHashCode(); 

    • Marked as answer by Zhi-Xin Ye Tuesday, December 2, 2008 8:20 AM
    Wednesday, November 26, 2008 2:46 PM

All replies

  • Disclamer I have no clue of inside knowledge to back up that this is actually a good idea or won't break in some edge cases but when you compare the method of the dynamically generated method it seems to do what you want (atleast for the two examles you gave):

    1. Expression<Func<Func<int,int>>> exp = () => x => x + 10 ;
    Func<Func<int,int>> compiled = exp.Compile();
    bool res = object.Equals( compiled().Method, compiled().Method );

    2. Func<int,int> f1 = x => x + 1;
    Func<int,int> f2 = x => x + 2;
    bool res = f1.Method.GetHashCode() == f2.Metod.GetHashCode(); 

    • Marked as answer by Zhi-Xin Ye Tuesday, December 2, 2008 8:20 AM
    Wednesday, November 26, 2008 2:46 PM
  • Hi Ray,

    Thanks for the response. At the moment I do something similar as a work arround for problem 2.

    I take a hash of both the Method and Target properties of the delegate and combine these. Unfortunately it doesn't help with problem 1. The Target property in the above example points to an 'ExecutionContext' object, which is a type of object that is "not intended to be used directly from your code". This is a different object after each invocation of 'compiled()'.
    This 'ExecutionContext' holds two arrays of 'Globals' and 'Locals' of type object[] but I think they always contain objects of type 'StrongBox<>' and I think these are references to external variables and constants.
    Unfortunately I see no way of checking wether two 'StrongBox<>' objects refer to the same constant or variable. And that would be vital to ensure  that the delegates are actually the same.

    As in this case; the method is the same but the ExecutionContexts are different. Different objects in the first place but both also
    having a StrongBox object refering to a different constant/variable, which is the important bit.

    Expression<Func<int,Func<int,int>>> exp = (inc) => x => x + inc ; //get StrongBox<> refering to inc.
    Func<int,Func<int,int>> compiled = exp.Compile();
    bool res = object.Equals( compiled(1).Method, compiled(2).Method ); //res is true.. same Method, but should have false. 

    So; at the moment I have a lot of different delegates, fortunately with a good hash. I'm hoping there is some way to compare the ExecutionContext properly so that I'll end up with a few different delegates with a good hash.

    Tx,

    Thomas.

    Wednesday, November 26, 2008 3:57 PM
  • Hi Tommie,

    Even though your approach works well, be aware that GetHashCode method produces uniques value ONLY within application domain. So if you try your approach with multiple domains you can get surprised...

    Vitaliy Liptchinsky http://dotnetframeworkplanet.blogspot.com/
    Monday, December 1, 2008 10:30 AM