Я прочитал около 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
для ссылочных типов, поскольку из того, что я видел, большинство ссылочных типов обычно не имеют неизменяемых полей, если они не хранятся в реляционной базе данных, чтобы идентифицировать их с их первичными ключами.