我已经阅读了大约 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
引用类型的用处,因为据我所见,大多数引用类型通常没有不可变字段,除非它们存储在关系数据库中以用它们的主键来识别它们。