【发布时间】:2018-03-01 17:43:04
【问题描述】:
我正在实现 IEquatable<T>,但我很难就可变类上的 GetHashCode 覆盖达成共识。
以下资源都提供了一个实现,如果对象发生变化,GetHashCode 将在对象的生命周期内返回不同的值:
- https://stackoverflow.com/a/13906125/197591
- https://csharp.2000things.com/tag/iequatable/
- http://broadcast.oreilly.com/2010/09/understanding-c-equality-iequa.html
然而,this link 声明 GetHashCode 不应该不为可变类型实现,因为如果对象是集合的一部分,它可能会导致不良行为(这一直是我的理解也是)。
有趣的是,MSDN example 仅使用不可变属性实现了GetHashCode,这符合我的理解。但我很困惑为什么其他资源没有涵盖这一点。他们只是错了吗?
如果一个类型根本没有不可变的属性,当我覆盖Equals(object) 时,编译器会警告GetHashCode 丢失。在这种情况下,我应该实现它并调用base.GetHashCode() 还是只禁用编译器警告,或者我错过了什么并且GetHashCode 应该始终被覆盖和实现?事实上,如果建议是不应该为可变类型实现GetHashCode,那么为什么还要为不可变类型实现呢?与默认的GetHashCode 实现相比,它只是为了减少冲突,还是实际上添加了更多有形的功能?
总结我的问题,我的困境是在可变对象上使用GetHashCode 意味着如果对象的属性发生变化,它可以在对象的生命周期内返回不同的值。但不使用它意味着失去了比较可能等效的对象的好处,因为它总是会返回一个唯一值,因此集合将总是回退到使用 Equals 进行操作。
输入此问题后,another Question 会出现在似乎解决同一主题的“类似问题”框中。那里的答案似乎很明确,因为在GetHashCode 实现中应该只使用不可变的属性。如果没有,那就干脆不写一个。 Dictionary<TKey, TValue> 仍然可以正常运行,尽管性能不是 O(1)。
【问题讨论】:
-
这是废话。仅当对象用作字典中的键或存储在哈希集中时才会出现问题。如果对象在存储后发生变异,则 GetHashCode 不应返回不同的值。也许您必须通过实际提供自定义 GetHashCode 来强制执行:)
-
@HansPassant 我同意,但自定义
GetHashCode必须仅使用不可变属性。否则,请使用默认值,根据我的问题的最后一段,它仍然允许Dictionary<TKey, TValue>正常运行,但没有它通常具有的 O(1) 性能。 -
@Neo,不,使用
GetHashCode()的默认实现,您的字典将无法正常工作。见this例子 -
@GianPaolo 那么要么这被认为是类型没有不可变属性的期望行为,要么有一个解决方案来覆盖
GetHashCode。在这个例子中你将如何实现GetHashCode?
标签: c# immutability mutable gethashcode iequatable