Сначала немного фона ...
Каждый объект в .NET имеет метод Equals и метод GetHashCode.
Метод Equals используется для сравнения одного объекта с другим объектом - чтобы определить, эквивалентны ли эти два объекта.
Метод GetHashCode генерирует 32-разрядное целочисленное представление объекта. Поскольку не существует ограничений на объем информации, которую может содержать объект, некоторые хеш-коды совместно используются несколькими объектами, поэтому хеш-код не обязательно является уникальным.
Словарь - это действительно классная структура данных, которая торгует большим объемом памяти в обмен на (более или менее) постоянные затраты на операции добавления / удаления / получения. Это плохой выбор для повторения, хотя. Внутри словарь содержит массив блоков, в которых могут храниться значения. Когда вы добавляете ключ и значение в словарь, для ключа вызывается метод GetHashCode. Возвращенный хэш-код используется для определения индекса корзины, в которой должна храниться пара ключ / значение.
Когда вы хотите получить доступ к значению, вы снова передаете ключ. Метод GetHashCode вызывается для ключа, и область памяти, содержащая значение, находится.
Когда IEqualityComparer передается в конструктор словаря, методы IEqualityComparer.Equals и IEqualityComparer.GetHashCode используются вместо методов объектов Key.
Теперь, чтобы объяснить, почему оба метода необходимы, рассмотрим следующий пример:
BoxEqualityComparer boxEqC = new BoxEqualityComparer();
Dictionary<Box, String> boxes = new Dictionary<Box, string>(boxEqC);
Box redBox = new Box(100, 100, 25);
Box blueBox = new Box(1000, 1000, 25);
boxes.Add(redBox, "red");
boxes.Add(blueBox, "blue");
Используя метод BoxEqualityComparer.GetHashCode в вашем примере, оба этих блока имеют одинаковый хэш-код - 100 ^ 100 ^ 25 = 1000 ^ 1000 ^ 25 = 25 - даже если они явно не являются одним и тем же объектом. Причина того, что они имеют одинаковый хэш-код в этом случае, заключается в том, что вы используете оператор ^ (побитовое исключающее-ИЛИ), поэтому 100 ^ 100 отменяет оставляя ноль, как и 1000 ^ 1000. Когда два разных объекта имеют одинаковый ключ, мы называем это столкновением.
Когда мы добавляем две пары ключ / значение с одним и тем же хеш-кодом в словарь, они обе сохраняются в одном и том же сегменте. Поэтому, когда мы хотим получить значение, в нашем ключе вызывается метод GetHashCode для определения области памяти. Поскольку в сегменте содержится более одного значения, словарь выполняет итерацию по всем парам ключ / значение в сегменте, вызывая метод Equals для ключей, чтобы найти правильное значение.
В приведенном вами примере два поля эквивалентны, поэтому метод Equals возвращает значение true. В этом случае в словаре есть два идентичных ключа, поэтому он выдает исключение.
TLDR
Итак, в итоге, метод GetHashCode используется для генерации адреса, где хранится объект. Таким образом, словарь не должен искать это. Он просто вычисляет хэш-код и переходит в это место. Метод Equals является лучшим тестом на равенство, но его нельзя использовать для сопоставления объекта с адресным пространством.
Надеюсь, это поможет