﻿# 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\.

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

Нарушение контракта методов [`GetHashCode`](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=net-10.0) и [`Equals`](https://learn.microsoft.com/en-us/dotnet/api/system.object.equals?view=net-8.0) может привести к некорректной работе некоторых функций и структур данных:

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

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

```cpp
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**\. Упростить сравнение объектов:

```cpp
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` также должен учитывать хэши объектов коллекции:

```cpp
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 может нарушить их\.