Почему C# не реализует GetHashCode для Наборов?

Я портирую что-то от Java до C#. В Java hashcode из a ArrayList зависит от объектов в нем. В C# я всегда получаю тот же хэш-код от a List...

Почему это?

Для некоторых моих объектов хэш-код должен отличаться, потому что объекты в их свойстве списка делают объекты неравными. Я ожидал бы, что хэш-код всегда уникален для состояния объекта и только равняется другому хэш-коду, когда объект равен.Я неправ?

17
задан Peterdk 9 August 2014 в 20:06
поделиться

6 ответов

Для корректной работы хэш-коды должны быть неизменяемыми - хэш-код объекта не должен никогда меняться.

Если хэш-код объекта изменится, все словари, содержащие этот объект, перестанут работать.

Поскольку коллекции не являются неизменяемыми, они не могут реализовать GetHashCode.
Вместо этого они наследуют стандартный GetHashCode, который возвращает (надеюсь) уникальное значение для каждого экземпляра объекта. (Обычно основанное на адресе памяти)

15
ответ дан 30 November 2019 в 11:32
поделиться

Невозможно, чтобы хэш-код был уникальным для всех вариаций большинства нетривиальных классов. В C# концепция равенства списков не такая, как в Java (см. здесь), поэтому реализация хэш-кода также не такая - она отражает равенство списков C#.

3
ответ дан 30 November 2019 в 11:32
поделиться

Вы ошибаетесь лишь отчасти. Вы определенно ошибаетесь, когда думаете, что одинаковые хэш-коды означают одинаковые объекты, но одинаковые объекты должны иметь одинаковые хэш-коды, что означает, что если хэш-коды различаются, то же самое происходит и с объектами.

2
ответ дан 30 November 2019 в 11:32
поделиться

Почему слишком философски. Создайте вспомогательный метод (может быть методом расширения) и рассчитайте хэш-код по своему усмотрению. Могут быть хэш-коды элементов XOR

0
ответ дан 30 November 2019 в 11:32
поделиться

Да, вы ошибаетесь. Как в Java, так и в C # равенство подразумевает наличие одного и того же хэш-кода, но обратное (не обязательно) верно.

См. GetHashCode для получения дополнительной информации.

8
ответ дан 30 November 2019 в 11:32
поделиться

Основными причинами являются производительность и человеческая природа - люди склонны думать о хэшах как о чем-то быстром, но обычно для этого требуется хотя бы один обход всех элементов объекта.

Пример: если вы используете строку в качестве ключа в хеш-таблице, каждый запрос имеет сложность O (| s |) - используйте строки в 2 раза длиннее, и это будет стоить вам как минимум в два раза дороже. Представьте, что это было развернутое дерево (просто список списков) - ой: -)

Если бы полное, глубокое вычисление хеша было стандартной операцией для коллекции, огромный процент программистов просто использовал бы его невольно, а затем обвинял бы framework и виртуальная машина за то, что они медленные. Для такой дорогостоящей задачи, как полный обход, крайне важно, чтобы программист осознавал всю сложность. Единственное, что нужно было добиться, - это убедиться, что вы должны написать свой собственный. Это тоже хороший сдерживающий фактор: -)

Еще одна причина - обновление тактики . Вычисление и обновление хэша «на лету» по сравнению с выполнением полного расчета каждый раз требует суждения в зависимости от конкретного случая.

Неизменность - это просто академическая отговорка - люди используют хеши для более быстрого обнаружения изменений (например, файловые хэши), а также используют хеши для сложных структур, которые постоянно меняются. У хеша есть гораздо больше применений, помимо основ 101. Ключевым моментом здесь снова является то, что то, что использовать для хеширования сложного объекта, должно быть решающим в каждом конкретном случае.

Использование адреса объекта (на самом деле дескриптора, поэтому он не меняется после сборки мусора) в качестве хэша на самом деле является случаем, когда значение хеш-функции остается неизменным для произвольного изменяемого объекта :-) Причина, по которой C # делает это, заключается в том, что он дешев и снова подталкивает людей рассчитывать свои собственные.

3
ответ дан 30 November 2019 в 11:32
поделиться