为什么哈希表和字典不使用 Equals() 方法而不是 GetHashCode 在 .NET 中进行键比较?

Why don't Hashtables and dictionaries use Equals() method instead of GetHashCode for keys comparision in .NET?

在 .NET 中,每当我们重写 class 的 Equals() 方法时,通常也会重写 GetHashCode() 方法。这样做可以确保在哈希表和字典中使用该对象时获得更好的性能。只有当它们的 GetHashCode() 值相同时,两个键才被认为在 Hashtable 中是相等的。我的问题是为什么 Hashtables 不能使用 Equals() 方法来比较键?,这将消除覆盖 GetHashCode() 方法的负担。

HastTable/Dictionaries 在发生冲突时使用 Equals (当两个哈希码相同时)

Why don't they use only Equals ?

因为这比访问/(比较)整数值值(哈希码)需要更多的处理。 (由于使用哈希码作为索引,所以复杂度为O(1))

A HashSet(或HashTable,或Dictionary)使用桶数组来分发项目,这些桶由对象的哈希码(应该是不可变的)索引), 所以搜索项目所在的桶是 O(1).

然后它在该桶中使用 Equals 来查找完全匹配,如果有多个项目具有相同的哈希码:那是 O(N) 因为它需要迭代该桶中的所有项目以找到比赛。

如果仅使用哈希集 Equals,查找项目的复杂度为 O(N),您也可以使用列表或数组。

这也是为什么两个相等的项目必须具有相同的哈希码,但具有相同哈希码的两个项目不一定要相等。

  • Two object instances that compare as equal must always have identical hash codes。如果这不成立,hash-based 数据结构 将无法正常工作 。这不是性能问题。
  • 两个不相等的对象实例最好具有不同的散列码。如果这不成立,hash-based 数据结构的性能将会下降,但至少它们仍然可以工作。

因此,对于给定的对象实例,GetHashCode需要在一定程度上反映Equals的逻辑。

现在,如果您要重写 Equals 方法,您就是在提供自定义比较逻辑。例如,假设您的自定义比较逻辑仅涉及实例的一个特定数据成员。要使 non-virtual GetHashCode 方法有用,它必须足够通用才能 理解 您的自定义 Equals 逻辑并能够提出当场使用自定义哈希码函数(仅涉及您选择的数据成员)。

编写如此复杂的 GetHashCode 并不容易,也不值得麻烦,因为用户可以简单地提供满足初始要求的自定义 one-liner。