HashCode
Algorithms
Programming
Coding Best Practices
Software Development

What is the best algorithm for overriding GetHashCode?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

There is no single magic GetHashCode algorithm that is best for every type. What matters is satisfying the equality contract, using the same fields as Equals, and producing a stable, fast hash for the lifetime of the object. In modern .NET, the practical default is HashCode.Combine, not a hand-written custom formula unless you have a specific reason.

Start With the Contract, Not the Formula

Before thinking about primes or XOR, keep the core rule in mind:

  • if two objects are equal, they must return the same hash code

The reverse is not required. Different objects are allowed to collide. A good hash reduces collisions, but correctness comes first.

That means GetHashCode and Equals must talk about the same identity fields.

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

This is usually the right level of sophistication.

Prefer HashCode.Combine in Modern .NET

For most application code, HashCode.Combine is the best default because it is:

  • concise
  • less error-prone than manual formulas
  • designed for common .NET use
csharp
1public override int GetHashCode()
2{
3    return HashCode.Combine(Id, Name, CreatedAt);
4}

This is clearer than maintaining a hand-rolled hash expression across future refactors.

Manual Prime Multiplication Still Works

If you are targeting older frameworks or want a classic explicit implementation, prime multiplication is still a solid pattern.

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

The unchecked block avoids overflow exceptions, which is normal for hash code composition.

This approach is fine. It is just more verbose and easier to get wrong than HashCode.Combine.

Why Simple XOR Is Usually Not the Best Default

XOR-based implementations are short, but they often lose information too easily, especially when field order matters or values repeat.

csharp
1public override int GetHashCode()
2{
3    return Field1.GetHashCode() ^ Field2.GetHashCode();
4}

This is not automatically wrong, but it is usually weaker than better combination strategies. For example, identical values can cancel each other out in ways that make collisions more likely.

So if you are choosing a general-purpose algorithm, XOR is rarely the first recommendation today.

Only Hash Immutable Identity Fields

A critical design rule is that fields used in GetHashCode should not change while the object is being used as a key in a hash-based collection.

Bad pattern:

csharp
1public sealed class User
2{
3    public string Name { get; set; } = "";
4
5    public override int GetHashCode() => Name.GetHashCode();
6}

If Name changes after the object is inserted into a Dictionary or HashSet, lookups can break because the object moves logically to a different hash bucket.

So the real best practice is not just algorithm choice. It is also choosing stable identity fields.

Records and Generated Hash Codes

If your type is a C# record, the compiler already generates value-based equality and hash code behavior.

csharp
public record Product(int Id, string Name);

In that case, you often should not override GetHashCode at all unless you have a very specific reason. Generated equality members are usually correct and maintainable for ordinary value objects.

Do Not Persist or Share Hash Codes as Business Data

A hash code is for in-memory hashing behavior, not for durable identifiers or cross-process protocol values. Hash implementations can differ across runtime versions or object types, and some built-in string hashing behavior is intentionally not something you should treat as a stable external identifier.

If you need a stable external hash, that is a different problem entirely and should use an explicit algorithm such as SHA-256 or another deliberate serialization-based approach.

Common Pitfalls

The biggest mistake is making Equals and GetHashCode use different fields. Another is hashing mutable properties and then using the object as a dictionary key. Developers also overfocus on clever formulas when HashCode.Combine would have been both clearer and safer. XOR-only hashes are another common shortcut that is usually not the strongest default. In day-to-day .NET code, the best "algorithm" is often simply choosing the right fields and combining them consistently.

Summary

  • The best GetHashCode implementation starts with the equality contract, not with a clever formula.
  • Equal objects must always return the same hash code.
  • In modern .NET, HashCode.Combine is usually the best default choice.
  • Prime multiplication is still a valid manual fallback.
  • Avoid hashing mutable fields if the object will be used in hash-based collections.
  • Do not treat GetHashCode values as stable external identifiers.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.