Я прочитал около 10 разных вопросов о том, когда и как переопределить GetHashCode, но я все еще кое-что не понимаю. Большинство реализаций GetHashCode основаны на хэш-кодах полей объекта, но было указано, что значение GetHashCode никогда не должно изменяться в течение времени существования объекта. Как это работает, если поля, на которых он основан, являются изменяемыми? Также что, если я хочу, чтобы поиск в словаре и т. Д. Был основан на равенстве ссылок, а не на моем переопределенном Equals?
Я в первую очередь переопределяю Equals для простоты модульного тестирования моего кода сериализации, который, как я предполагаю, сериализация и десериализация (в моем случае в XML) убивает эталонное равенство, поэтому я хочу убедиться, что, по крайней мере, он верен по равенству значений. Является ли в данном случае плохой практикой отменять Equals? В основном в большей части исполняемого кода мне нужно ссылочное равенство, и я всегда использую ==, и я не отменяю это. Должен ли я просто создать новый метод ValueEquals или что-то в этом роде вместо того, чтобы заменять Equals? Раньше я предполагал, что фреймворк всегда использует ==, а не Equals для сравнения вещей, и поэтому я подумал, что можно безопасно переопределить Equals, поскольку мне казалось, что его цель заключалась в том, если вы хотите иметь второе определение равенства, отличное от == оператор. Однако, прочитав несколько других вопросов, кажется, что это не так.
РЕДАКТИРОВАТЬ:
Кажется, мои намерения были неясны, я имею в виду, что в 99% случаев мне нужно простое старое ссылочное равенство, поведение по умолчанию, никаких сюрпризов. В очень редких случаях я хочу иметь равенство значений, и я хочу явно запросить равенство значений, используя .Equals вместо ==.
Когда я делаю это, компилятор рекомендует также переопределить GetHashCode, и вот как возник этот вопрос. Казалось, что цели GetHashCode в применении к изменяемым объектам противоречат друг другу, а именно:
- Если
a.Equals(b), тоa.GetHashCode()должен== b.GetHashCode(). - Значение
a.GetHashCode()никогда не должно изменяться в течение срока жизниa.
Это кажется естественным противоречием для изменяемого объекта, потому что, если состояние объекта изменяется, мы ожидаем, что значение .Equals() изменится, что означает, что GetHashCode должно измениться, чтобы соответствовать изменению в .Equals(), но GetHashCode не должно измениться.
Почему возникает это противоречие? Не предназначены ли эти рекомендации для применения к изменяемым объектам? Вероятно, предполагалось, но, возможно, стоит упомянуть, что я имею в виду классы, а не структуры.
Разрешение:
Я отмечаю JaredPar как принятый, но в основном для взаимодействия с комментариями. Подводя итог тому, что я узнал из этого, заключается в том, что единственный способ достичь всех целей и избежать возможного причудливого поведения в крайних случаях - это только переопределить Equals и GetHashCode на основе неизменяемых полей или реализовать IEquatable. Этот вид, кажется, уменьшает полезность переопределения Equals для ссылочных типов, поскольку, как я видел, большинство ссылочных типов обычно не имеют неизменяемых полей, если они не хранятся в реляционной базе данных, чтобы идентифицировать их с их первичными ключами.