IEqualityComparer <T>GetHashCode возвращает одинаковые значения, когда элементы не равны? - PullRequest
0 голосов
/ 05 октября 2011

В разделе «Примечания для разработчиков» в документации по методу GetHashCode интерфейса IEqualityComparer<T> указано:

Реализации необходимы для обеспечения того, чтобы, если метод Equals возвращает true для двух объектов x и y, затем значение, возвращаемое Метод GetHashCode для x должен равняться значению, возвращенному для y.

Хорошо известно, почему вы хотите, чтобы два экземпляра T возвращали один и тот же хеш-код, если два элемента равны; их различие означало бы, что они не равны, а то, что они одинаковы, означает, что они потенциально равны.

Я интерпретирую кавычку как неопределенную для возвращаемого значения, когда два экземпляра не равны (хотя их значения могут указывать на это).

Возьмем, к примеру, следующее. У меня есть последовательность int?, которую я хочу использовать для статистической классификации , где каждый ненулевой int? представляет атрибут класса (думаю, перечислите значения). В случае, когда эти значения являются нулевыми, вы не хотите, чтобы значения считались равными, поскольку они сместили бы тренировочный набор в сторону пропущенных значений. Во всяком случае, вы бы хотели, чтобы в этом случае нулевые значения при сравнении с другими нулевыми значениями возвращали false.

Дело в том, что в методе GetHashCode, когда ему дано значение NULL, я, вероятно, захочу вернуть 0 (или какое-то другое число, например Int32.MinValue). Теперь я знаю, что когда что-то вводится с помощью этой реализации IEqualityComparer<T>, производительность для проверки наличия ключа в словаре не будет оптимальной для этих случаев.

Тем не менее, допустимо ли возвращать значение, о котором известно, что оно конфликтует, с другими значениями, когда вызывается GetHashCode, когда вызов Equals возвращает false? Я склоняюсь к да, так как приведенная выше цитата не определена в этом вопросе.

Ответы [ 3 ]

7 голосов
/ 05 октября 2011

Это абсолютно необходимо для почти всех типов, так как должно быть два значения v1 и v2, таких что

v1.Equals(v2) == false
v1.GetHashCode() == v2.GetHashCode()

... или эквивалент с IEqualityComparer<T>. Единственные случаи, когда не , - это случаи, когда существует не более 2 32 различных (не равных) значений. Как только будет получено больше значений, принцип голубиных вынуждает повторно использовать хэш-коды - хэш-кодов просто недостаточно для обхода!

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

Кстати, проблема нулей интересна. IEqualityComparer<T> позволяет GetHashCode генерировать исключение, но я считаю, что встроенные реализации Comparer<T> никогда не делают. Похоже, у вас есть одна проблема - Equals должно быть рефлексивным - поэтому нулевое значение должно быть равным самому себе. Возможно, вам следует тщательно обдумать этот вопрос ... можете ли вы представить «разные» нулевые значения?

2 голосов
/ 05 октября 2011

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

1 голос
/ 05 октября 2011

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

Например, возьмите словарь, индексированный без учета регистра, и скажите, что ваша реализация GetHashCode возвращает значение первого символа. Таким образом, «A» и «a» равны, но имеют разные значения хеша (65 и 97). Другими словами: вы нарушаете правило. Если вы затем делаете что-то вроде:

dict["A"] = "something";
Console.WriteLine(dict["a"]);

тогда вторая строка, скорее всего, потерпит неудачу с KeyNotFoundException, даже если ключи "A" и "a" равны.

...