4

我使用一些包含 1-2 个整数的身份类/结构,也可能是一个日期时间或一个小字符串。我将这些用作字典中的键。

对于这样的事情,什么是对 GetHashCode 的良好覆盖?一些非常简单但仍然希望有一些性能的东西。

谢谢

4

1 回答 1

1

看看Essential C#

它包含有关如何GetHashCode()正确覆盖的详细说明。

从书中摘录

哈希码的目的是通过生成与对象的值对应的数字来有效地平衡哈希表。

  • 必需:相等的对象必须具有相等的哈希码(如果a.Equals(b),那么a.GetHashCode() == b.GetHashCode()
  • 必需: GetHashCode()即使对象的数据发生变化,特定对象生命周期内的返回值也应该是常量(相同的值)。在许多情况下,您应该缓存方法返回以强制执行此操作。
  • 必需: GetHashCode()不应抛出任何异常;GetHashCode()必须始终成功返回一个值。
  • 性能:哈希码应尽可能唯一。但是,由于哈希码只返回一个int,因此对于具有可能比 int 可以容纳的更多值的对象(几乎所有类型)的哈希码必须存在重叠。(一个明显的例子是long,因为可能的long值比int唯一标识的要多。)
  • 性能:可能的哈希码值应均匀分布在int. 例如,创建一个不考虑在基于拉丁语的语言中字符串的分布主要集中在最初的 128 个 ASCII 字符这一事实的哈希将导致字符串值的分布非常不均匀,并且不是一个强大的GetHashCode()算法。
  • 性能: GetHashCode()应针对性能进行优化。GetHashCode()如果哈希码不同,通常在Equals()实现中用于短路完全等于比较。因此,当该类型用作字典集合中的键类型时,它经常被调用。
  • 性能:两个对象之间的微小差异应该会导致哈希码值之间的巨大差异——理想情况下,对象中的 1 位差异会导致哈希码平均发生大约 16 位的变化。这有助于确保散列表保持平衡,无论它如何“存储”散列值。
  • 安全性:攻击者应该很难制作具有特定哈希码的对象。攻击是用大量数据淹没哈希表,这些数据都哈希到相同的值。然后哈希表实现变为 O(n) 而不是 O(1),从而导致可能的拒绝服务攻击。

正如这里已经提到的,您还必须考虑有关覆盖的一些要点,Equals()并且有一些代码示例显示了如何实现这两个功能。

所以这些信息应该是一个起点,但我建议购买这本书并阅读完整的第 9 章(至少前十二面),以了解如何正确实现这两个关键功能的所有要点。

于 2010-07-08T13:46:25.167 回答