C#
GetHashCode
Method Overriding
Object Method
`Hash` Codes

C Overriding the GetHashCode method

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In C#, you override GetHashCode when your type defines value-based equality and you want hash-based collections such as Dictionary and HashSet to behave correctly. The rule is strict: if two objects are equal according to Equals, they must return the same hash code.

GetHashCode and Equals are a pair

A hash code is not a unique identifier. It is a compact value used to place objects into hash buckets efficiently. Collisions are allowed. What is not allowed is this:

  • 'x.Equals(y) is true'
  • but x.GetHashCode() and y.GetHashCode() are different

That breaks the assumptions used by hash-based collections.

So if you override GetHashCode, you usually also override Equals.

A simple value-object example

csharp
1using System;
2
3public sealed class Person
4{
5    public string FirstName { get; }
6    public string LastName { get; }
7
8    public Person(string firstName, string lastName)
9    {
10        FirstName = firstName;
11        LastName = lastName;
12    }
13
14    public override bool Equals(object? obj)
15    {
16        return obj is Person other
17            && FirstName == other.FirstName
18            && LastName == other.LastName;
19    }
20
21    public override int GetHashCode()
22    {
23        return HashCode.Combine(FirstName, LastName);
24    }
25}

This is the common modern pattern: compare the same fields in Equals that you combine in GetHashCode.

Use immutable fields whenever possible

Hash-based collections assume that the hash code of an object does not change while the object is being used as a key. That is why immutable fields are strongly preferred in equality and hash-code logic.

If you base the hash on mutable properties and then change one of them after inserting the object into a HashSet or Dictionary, lookups may stop working as expected.

That is one of the most common real-world bugs in custom hash-code implementations.

HashCode.Combine is the easiest modern approach

Older C# code often used manual prime multiplication patterns. That still works, but HashCode.Combine is usually clearer and less error-prone.

Manual approach:

csharp
1public override int GetHashCode()
2{
3    unchecked
4    {
5        int hash = 17;
6        hash = hash * 23 + (FirstName?.GetHashCode() ?? 0);
7        hash = hash * 23 + (LastName?.GetHashCode() ?? 0);
8        return hash;
9    }
10}

Modern approach:

csharp
1public override int GetHashCode()
2{
3    return HashCode.Combine(FirstName, LastName);
4}

The important thing is consistency with Equals, not nostalgia for a manual formula.

Do not optimize for uniqueness

A good hash code should distribute values reasonably, but it is not required to be unique. Two unequal objects may share the same hash code. Collections handle collisions internally.

That means you should not overengineer the method trying to eliminate all collisions. Focus on correctness and reasonable distribution.

Records already solve much of this

If your type is a simple value-like data carrier, a C# record often generates the equality and hashing behavior you want automatically.

csharp
public record Person(string FirstName, string LastName);

That is often better than manually overriding both methods on a trivial value object.

Common Pitfalls

  • Overriding GetHashCode without also making Equals consistent.
  • Including mutable fields in the hash code for objects used as dictionary keys.
  • Assuming hash codes must be unique for unequal objects.
  • Recomputing hash from fields that are not part of logical equality.
  • Writing elaborate custom hash formulas when HashCode.Combine or a record would be simpler.

Summary

  • Override GetHashCode when your type has value-based equality.
  • Keep GetHashCode consistent with Equals.
  • Prefer immutable fields for values used in hashing.
  • 'HashCode.Combine is the normal modern implementation tool.'
  • For simple value objects, consider using records instead of manual overrides.

Course illustration
Course illustration

All Rights Reserved.