When do we do GetHashCode() for a Dictionary?

Just to make it clear: There is one important thing about Dictionary<TKey, TValue> and GetHashCode(): Dictionary uses GetHashCode to determine if two keys are equal i.e. if <TKey> is of custom type you should care about implementing GetHashCode() carefully. As Andrew Hare pointed out this is easy, if you have a simple type that identifies your custom object unambiguously. In case you have a combined identifier, it gets a little more complicated.

As example consider a complex number as TKey. A complex number is determined by its real and its imaginary part. Both are of simple type e.g. double. But how would you identify if two complex numbers are equal? You implement GetHashCode() for your custom complex type and combine both identifying parts.

You find further reading on the latter here.

UPDATE

Based on Ergwun's comment I checked the behavior of Dictionary<TKey, TValue>.Add with special respect to TKey's implementation of Equals(object) and GetHashCode(). I must confess that I was rather surprised by the results.

Given two objects k1 and k2 of type TKey, two arbitrary objects v1 and v2 of type TValue, and an empty dictionary d of type Dictionary<TKey, TValue>, this is what happens when adding v1 with key k1 to d first and v2 with key k2 second (depending on the implementation of TKey.Equals(object) and TKey.GetHashCode()):

k1.Equals(k2)   k1.GetHashCode() == k2.GetHashCode()   d.Add(k2, v2)
false           false                                  ok
false           true                                   ok
true            false                                  ok
true            true                                   System.ArgumentException

Conclusion: I was wrong as I originally thought the second case (where Equals returns false but both key objects have same hash code) would raise an ArgumentException. But as the third case shows dictionary in some way does use GetHashCode(). Anyway it seems to be good advice that two objects that are the same type and are equal must return the same hash code to ensure that instances Dictionary<TKey, TValue> work correctly.


You have two questions here.

  1. When do you need to implement GetHashCode()
  2. Would you ever use an object for a dictionary key.

Lets start with 1. If you are writing a class that might possibly be used by someone else, you will want to define GetHashCode() and Equals(), when reference Equals() is not enough. If you're not planning on using it in a dictionary, and it's for your own usage, then I see no reason to skip GetHashCode() etc.

For 2), you should use an object anytime you have a need to have a constant time lookup from an object to some other type. Since GetHashCode() returns a numeric value, and collections store references, there is no penalty for using an Object over an Int or a string (remember a string is an object).


You should override Equals and GetHashCode whenever the default Object.Equals (tests for reference equality) will not suffice. This happens, for example, when the type of your key is a custom type and you want two keys to be considered equal even in cases when they are not the same instance of the custom type.

For example, if your key is as simple as

class Point {
    public int X { get; set; }
    public int Y { get; set; }
}

and you want two Points two be considered equal if their Xs are equal and their Ys are equal then you will need to override Equals and GetHashCode.

Tags:

C#

.Net