Why is it important to override GetHashCode when Equals method is overridden?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When you override Equals in C#, you must also override GetHashCode to maintain the contract that equal objects produce the same hash code. Hash-based collections like Dictionary<TKey, TValue>, HashSet<T>, and Hashtable use GetHashCode() to determine which bucket an object belongs to before calling Equals() to confirm a match. If two objects are equal by Equals() but return different hash codes, the collection places them in different buckets and treats them as distinct — causing lookups, containment checks, and deduplication to fail silently.
The Contract
The .NET documentation states two rules:
- If
a.Equals(b)returnstrue, thena.GetHashCode()must equalb.GetHashCode() - The reverse is not required — objects with the same hash code may not be equal (hash collisions are allowed)
What Goes Wrong Without GetHashCode
The Dictionary and HashSet first compute GetHashCode() to find the bucket, then call Equals() only on items in that bucket. Since point1 and point2 have different hash codes, they go to different buckets, and Equals() is never called.
Correct Implementation
How to Implement GetHashCode
Using HashCode.Combine (Recommended, .NET Core 2.1+)
Using HashCode.Add for Many Fields
Manual Implementation (Older .NET)
The unchecked block allows integer overflow without throwing, and the prime multipliers (17, 31) help distribute hash codes evenly across buckets.
Records: Automatic Implementation
C# 9 records generate both Equals and GetHashCode automatically:
Records implement value-based equality by default, with correctly paired Equals and GetHashCode.
What Fields to Include
Include the same fields in GetHashCode that you use in Equals:
If Equals uses Id and Name but GetHashCode only uses Id, the contract is still satisfied (equal objects still produce equal hash codes). But if GetHashCode uses a field that Equals does not, the contract can break.
Common Pitfalls
- Overriding
EqualswithoutGetHashCode: The compiler emits warning CS0659 for this exact situation. Hash-based collections silently fail — lookups return false, duplicate entries appear in sets, and dictionary keys become unreachable. - Including mutable fields in
GetHashCode: If a field used inGetHashCodechanges while the object is in aDictionaryorHashSet, the hash code changes but the object stays in the old bucket. The object becomes unfindable. Use only immutable fields, or do not mutate objects while they are in hash-based collections. - Returning a constant hash code:
return 0;satisfies the contract but forces every object into the same bucket, turning O(1) lookups into O(n) linear scans. Hash codes should distribute evenly. - Using different fields in
EqualsandGetHashCode: IfEqualscompares fields A and B butGetHashCodeuses fields A and C, two objects that are equal (same A and B, different C) may produce different hash codes, breaking the contract. - Forgetting null checks for reference fields:
field.GetHashCode()throwsNullReferenceExceptioniffieldis null. Usefield?.GetHashCode() ?? 0orHashCode.Combine()which handles nulls automatically.
Summary
- If
Equalsreturns true,GetHashCodemust return the same value for both objects - Hash-based collections (
Dictionary,HashSet) useGetHashCodeto find buckets before callingEquals - Use
HashCode.Combine()for a correct, well-distributed implementation - Include exactly the same fields in
GetHashCodethat you use inEquals - Never include mutable fields in
GetHashCodeif objects are stored in hash-based collections - C# records generate correct
EqualsandGetHashCodeautomatically

