Хорошо, прежде чем ты будешь сумасшедшим, потому что в Интернете есть сотни похожих звуковых вопросов, я могу заверить вас, что я провел последние несколько часов, читая их все и не нашел ответа на мой вопрос.
Справочная информация:
В принципе, одно из моих приложений большого масштаба страдает от ситуации, когда некоторая Binding
в свойстве ListBox.SelectedItem
перестала работать или программа сработала после внесения изменений в текущий выбранный элемент. Сначала я спросил "Элемент с тем же ключом уже добавлен" Исключение при выборе объекта ListBoxItem из кода здесь, но не получил ответов.
У меня не было времени решить эту проблему до этой недели, когда мне дали несколько дней, чтобы разобраться. Теперь, чтобы сократить длинную историю, я выяснил причину проблемы. Это связано с тем, что классы типов данных переопределили метод Equals
и, следовательно, метод GetHashCode
.
Теперь для тех из вас, кто не знает об этой проблеме, я обнаружил, что вы можете реализовать только метод GetHashCode
, используя неизменяемые поля/свойства. Используя отрывок из Harvey Kwok, ответьте на Переопределение сообщения GetHashCode(), чтобы объяснить это:
Проблема заключается в том, что GetHashCode используется сборками Dictionary и HashSet для размещения каждого элемента в ведре. Если hashcode вычисляется на основе некоторых изменяемых полей, и поля действительно изменяются после того, как объект помещен в HashSet или Dictionary, объект больше не может быть найден из HashSet или Dictionary.
Таким образом, фактическая проблема была вызвана тем, что я использовал изменчивые свойства в методах GetHashCode
. Когда пользователи изменили эти значения свойств в пользовательском интерфейсе, соответствующие значения хэш-кода объектов изменились, а затем элементы больше не могли быть найдены в их коллекциях.
Вопрос:
Итак, мой вопрос - это лучший способ справиться с ситуацией, когда мне нужно реализовать метод GetHashCode
в классах без обязательных полей? Извините, позвольте мне быть более конкретным, поскольку этот вопрос был задан раньше.
Ответы в Переопределении GetHashCode() позволяют предположить, что в этих ситуациях лучше просто вернуть постоянное значение... некоторые предлагают вернуть значение 1
, в то время как другие предлагают вернуть простое число. Лично я не вижу никакой разницы между этими предложениями, потому что я бы подумал, что для любого из них будет только один ковш.
Кроме того, Рекомендации и правила для GetHashCode в блоге Eric Lippert имеет раздел под названием Guideline: распределение хэш-кодов должно быть "случайный", который подчеркивает подводные камни использования алгоритма, который приводит к тому, что используется недостаточно ведра. Он предупреждает об алгоритмах, которые уменьшают количество используемых ведра и вызывают проблемы с производительностью, когда ведро становится действительно большим. Конечно, возвращение константы попадает в эту категорию.
У меня возникла идея добавить дополнительное поле Guid
ко всем моим типам типов данных (только в С#, а не в базу данных), специально предназначенную для использования только в методе GetHashCode
. Итак, я полагаю, что в конце этого длинного вступления, мой фактический вопрос заключается в том, какая реализация лучше? Подводя итог:
Резюме:
При переопределении Object.GetHashCode() в классах без неизменяемых полей лучше возвращать константу из метода GetHashCode
или создавать дополнительное поле readonly
для каждого класса, исключительно для использования в GetHashCode
метод? Если я должен добавить новое поле, какой тип должен быть, и не должен ли я включить его в метод Equals
?
В то время как я рад получить ответы от кого-либо, я действительно надеюсь получить ответы от продвинутых разработчиков с хорошими знаниями по этому вопросу.