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