In .NET, when you override the Equals()
method, it's recommended to also override GetHashCode()
. The reason is related to how .NET uses GetHashCode in its built-in data structures.
When you store an object in a hash-based collection like Dictionary
or HashSet
, .NET uses the value returned by GetHashCode()
to organize its data. Objects that are considered equal should return the same hash code, providing optimal performance when retrieving objects from such a collection.
If you override Equals()
, you're changing the definition of what makes two objects equal. So, if you don't also override GetHashCode()
, objects that you consider "equal" may return different hash codes. This can lead to inconsistent behavior when objects are used in a hash-based collection. They might not be found in the collection, even though you know they're there, because the collection is looking in the wrong hash bucket.
Let's see an example. Suppose, you have a Person
class and you have overridden Equals()
to say that two Person
objects are equal if their Name
property matches. But you forgot to override GetHashCode()
. Now, if you add a Person
object with Name="John"
to a HashSet
, and later try to check if the Person
object with Name="John"
exists in the HashSet
, it might return false
, which is incorrect, because the GetHashCode()
might be returning the hash code of the object reference, not the Name
string which you're using for equality comparison.
To avoid this issue, anytime you override Equals()
, you should also override GetHashCode()
to ensure it uses the same properties that Equals()
does. This will help maintain consistency when using hash-based collections.
Overriding GetHashCode()
requires producing a hash code that considers the same properties used in Equals()
, and is also evenly distributed to prevent hash collisions.
Here is one example of how you might achieve this:
public override int GetHashCode()
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = (hash * 23) + field1.GetHashCode();
hash = (hash * 23) + field2.GetHashCode();
return hash;
}
In this example, field1
and field2
are the fields that the Equals()
method checks. The constants 17
and 23
are just arbitrarily chosen 'magic' numbers that often give good results.
You can also use HashCode.Combine()
in C# 8.0 and later:
public override int GetHashCode()
{
return HashCode.Combine(field1, field2);
}
Remember, the goal of GetHashCode()
is not to avoid collisions entirely, but to distribute them evenly. Collisions are inevitable because the number of possible hash codes (2^32
for int
) is smaller than the number of possible string values, for example. But a good hash function will help ensure a more even distribution of hash code values and reduce the probability of collision, resulting in better performance when using hash-based collections.