C#
hashcode
array
integers
programming

C hashcode for array of ints

Master System Design with Codemia

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

Introduction

In C#, an int[] is a reference type, so its default hash code is based on object identity, not on the numbers inside the array. That matters when you want two arrays with the same contents to behave as equal keys in a dictionary or set.

Default Array Hash Codes Are Not Content-Based

Consider two different arrays that hold the same values:

csharp
1var a = new[] { 1, 2, 3 };
2var b = new[] { 1, 2, 3 };
3
4Console.WriteLine(a.GetHashCode() == b.GetHashCode());
5Console.WriteLine(a.Equals(b));

Both lines are typically False. The arrays contain the same integers, but they are different objects. By default, int[] equality is reference equality, and the hash code follows that same identity-based rule.

If you need content-based behavior, you must supply it yourself.

Use a Custom Comparer for Dictionaries and Sets

The usual fix is to implement IEqualityComparer<int[]> and compute the hash from the elements.

csharp
1using System;
2using System.Collections.Generic;
3
4public sealed class IntArrayComparer : IEqualityComparer<int[]>
5{
6    public bool Equals(int[]? x, int[]? y)
7    {
8        if (ReferenceEquals(x, y)) return true;
9        if (x is null || y is null) return false;
10        if (x.Length != y.Length) return false;
11
12        for (int i = 0; i < x.Length; i++)
13        {
14            if (x[i] != y[i]) return false;
15        }
16
17        return true;
18    }
19
20    public int GetHashCode(int[] obj)
21    {
22        var hash = new HashCode();
23
24        foreach (var value in obj)
25        {
26            hash.Add(value);
27        }
28
29        return hash.ToHashCode();
30    }
31}

Now you can use the comparer with a dictionary:

csharp
1var dictionary = new Dictionary<int[], string>(new IntArrayComparer())
2{
3    [new[] { 1, 2, 3 }] = "first"
4};
5
6Console.WriteLine(dictionary.TryGetValue(new[] { 1, 2, 3 }, out var value));
7Console.WriteLine(value);

That lookup succeeds because equality and hashing are both based on array contents.

Why HashCode Is a Good Modern Choice

Older examples often multiply by primes manually:

csharp
1public int GetHashCode(int[] obj)
2{
3    int hash = 17;
4    foreach (var value in obj)
5    {
6        hash = hash * 31 + value;
7    }
8    return hash;
9}

This works, and it is still a reasonable pattern. In modern C#, the HashCode type is usually cleaner and communicates intent better. It also avoids hand-rolling a mixing strategy unless you have a specific reason to do so.

Equality and Hash Code Must Match

The most important rule is consistency:

  • if two arrays are equal by your comparer, they must produce the same hash code
  • if two arrays have the same hash code, they are not required to be equal

That second point surprises people. Hash collisions are allowed. A hash code only narrows the search; equality decides the final answer.

This is why implementing only GetHashCode is not enough. If you want content-based behavior, Equals must compare the elements too.

Beware of Mutable Keys

Arrays are mutable. That makes them risky as dictionary keys even with a correct comparer.

csharp
1var key = new[] { 1, 2, 3 };
2var dict = new Dictionary<int[], string>(new IntArrayComparer())
3{
4    [key] = "value"
5};
6
7key[0] = 99;

After mutation, the dictionary can behave unexpectedly because the stored key's logical hash has changed. For that reason, immutable key types are often safer than raw arrays. If the data is supposed to represent a stable value, consider using an immutable collection or a small wrapper type that never exposes mutation.

When You Do Not Need a Custom Hash Code

If you are only printing, comparing manually, or doing one-off checks, you may not need a custom comparer at all. For example:

csharp
bool same = a.SequenceEqual(b);

That solves equality for a single comparison. The custom hash code becomes necessary when the array participates in hash-based collections such as Dictionary or HashSet.

Common Pitfalls

  • Expecting int[] to compare by contents automatically. It does not.
  • Overriding only hashing logic but not equality logic.
  • Using mutable arrays as keys and then changing them after insertion.
  • Forgetting to handle null in a custom comparer.
  • Assuming equal hash codes prove equality. They only mean the values share a bucket candidate.

Summary

  • The default hash code for int[] is based on reference identity, not the array contents.
  • For content-based dictionary or set behavior, provide an IEqualityComparer<int[]>.
  • A good comparer must implement both element-wise Equals and consistent GetHashCode.
  • 'HashCode is a clean modern way to combine element hashes.'
  • Mutable arrays are fragile keys, so prefer immutable value types when possible.

Course illustration
Course illustration

All Rights Reserved.