Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
V3229. The 'GetHashCode' method may...
menu mobile close menu
Проверка проектов
Дополнительная информация
toggle menu Оглавление

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.

02 Дек 2025

Анализатор обнаружил, что результат GetHashCode зависит от хэш-кода ссылки на некоторый объект. При этом результат Equals зависит от логики сравнения этого объекта, отличной от сравнения двух ссылок. Это может привести к нарушению контракта: два одинаковых объекта согласно методу Equals должны также иметь одинаковые хэш-коды.

Нарушение контракта методов GetHashCode и Equals может привести к некорректной работе некоторых функций и структур данных:

  • коллекции вроде HashSet и Dictionary;
  • LINQ-методы, такие как Union, Intersect и пр.

Рассмотрим пример:

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();
}

В качестве возвращаемого значения GetHashCode некоторого класса используется хэш-код от ссылки на коллекцию Values. При этом в методе Equals происходит поэлементное сравнение с этой коллекцией с помощью SequenceEqual.

Способ N1. Упростить сравнение объектов:

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();
}

Способ N2. Алгоритм в GetHashCode также должен учитывать хэши объектов коллекции:

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));
}

Вызов Aggregate формирует общий хэш-код элементов коллекции путём их перебора и обновления значения hash на каждой итерации согласно функции, переданной вторым аргументом.

Примечание. Необходимо также учитывать, что к методу GetHashCode предъявляются требования по скорости работы, а способ N2 может нарушить их.