Question

Concerning IEqualityComparer, is there ever a reason why the Equals(T x, T y) implementation should be anything other than what I have below?

public class MyEquality : IEqualityComparer<MyType>
{
    //My Equals(T x, T y) always looks like this
    public bool Equals(MyType x, MyType y)
    {
        return this.GetHashCode(x).Equals(this.GetHashCode(y));
    }

    public int GetHashCode(MyType obj)
    {
        //assume MyType has a non-nullable member called ID
        return obj.ID.GetHashCode();
    }
}
Was it helpful?

Solution

Yes. Hash codes can collide and in fact, they will with many types. They only exist to ensure equidistribution of values in hash tables, they are not useful for determining equality of values. Eric Lippert has also a take on this (and another one):

It is a really bad idea to use 32 bit hash codes as “unique” identifiers. Hash values aren't random per se, but if they're well-distributed then they might as well be for our purposes. You might think “well, sure, obviously they are not truly unique since there are more than four billion possible values, but only four billion hash codes available. But there are so many possible hash values, odds are really good that I’m going to get unique values for my hashes”. But are the chances really that good? 9300 objects is not that many and 1% is a pretty high probability of collision.

That being said, if your ID is the only thing you care for when determining equality, then comparing that ID should suffice. But not its hash code because a hash code only says

a.GetHashCode() ≠ b.GetHashCode() → ab

Note that nothing is said about the case where the hash code is the same.

OTHER TIPS

Yes, there is: if ID's hash code does not fit in an int, now or some time in the future, you would be in for a nasty surprise, when unequal objects with identical hash codes start evaluating as equals. If at a later date someone decides that ID should be long or Guid, MyEquality would continue to happily compile, but its behavior would be hopelessly incorrect.

On an unrelated note, if MyType is a class, you may want to do something about preventing crashes when x or y is null: although the contract of IEqualityComparer<T> does not explicitly calls for it (unlike object.Equals that does) it is a good idea to deal with nulls in IEqualityComparer<T>.Equals in situations when you search through containers that may include null objects.

Sure. You could have an object where you're only concerned about one or more properties being the same to consider them equal for your purposes.

If you would compare List list1, and List list2, if they have some "common" element, for instance list1={"apparent", "obvious"}, and list2={"aPPARENT", "oBVIOUS"}

if your definition of equity is as follows:

  • the first character must be equal, case sensitive
  • the remainder character must not be equal (case sensitive)

you must define your own logic in your IEqualityComparer.

Besides, in LINQ, all the Where, Any, Except, Intersect etc. clauses may require additional IEqualityComparer object for you to hook you custom logic.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top