Our website uses cookies to enhance your browsing experience.
Accept
to the top
>
>
>
V3229. The 'GetHashCode' method may...
menu mobile close menu
Additional information
toggle menu Contents

V3229. The 'GetHashCode' method may return different hash codes for equal objects. It uses an object reference to generate a hash for a variable. Check the implementation of the 'Equals' method.

Dec 02 2025

The analyzer has detected that the GetHashCode result depends on the hash code of a reference to an object, while the Equals result depends on that object's comparison logic, which differs from comparing two references. This mismatch can break the contract: if Equals considers two objects equal, they should also have the same hash code.

Breaking the contract of the GetHashCode and Equals methods can cause several functions and data structures to malfunction, including:

  • collections like HashSet and Dictionary;
  • LINQ methods such as Union, Intersect, and others.

The example:

public HashSet<Value> Values { get; private set; }  = new();
....
public override bool Equals(object obj)
{
  if (obj is not CustomObject other)
    return false;

  return Values.SequenceEqual(other.Values);
}

public override int GetHashCode()
{
  return Values.GetHashCode();
}

The hash code from the reference to the Values collection is used as the return value of GetHashCode for some class, while Equals compares the contents of that collection element-by-element using SequenceEqual.

Option 1. Simplify the object comparison:

public HashSet<Value> Values { get; private set; } = new();
....
public override bool Equals(object obj)
{
  if (obj is not CustomObject other)
    return false;

  return Values.Equals(other.Values);
}

public override int GetHashCode()
{
  return Values.GetHashCode();
}

Option N2. Ensure that the algorithm in GetHashCode also considers the hash codes of the collection elements:

public readonly HashSet<Value> Values { get; private set; } = new();
....
public override bool Equals(object obj)
{
  if (obj is not CustomObject other)
    return false;

  return Values.SequenceEqual(other.Values);
}

public override int GetHashCode()
{
  return Values.Aggregate(0,
           (hash, val) =>   (hash * 397) 
                          ^ (val?.GetHashCode() ?? 0));
}

The Aggregate call creates a single hash code for the collection by iterating through its elements and updating hash at each step according to the function that was passed as the second argument.

Note. The GetHashCode function must run quickly, and option N2 may not meet that requirement.