【问题标题】:When does Dictionary<TKey, TValue> call TKey.Equals()?Dictionary<TKey, TValue> 何时调用 TKey.Equals()?
【发布时间】:2009-10-13 18:05:58
【问题描述】:

只是在TKey 中覆盖Equals 并没有帮助。

public override bool Equals(object obj)
{ /* ... */  }

...Equals() 永远不会被调用...

【问题讨论】:

    标签: c# .net dictionary


    【解决方案1】:

    当您进行字典查找时,事情发生的顺序是这样的:

    1. 字典使用 TKey.GetHashCode 计算存储桶的哈希值。
    2. 然后,它使用该存储桶检查所有哈希值,并对各个对象调用 Equals 以确定匹配。

    如果桶永远不匹配(因为 GetHashCode 没有被覆盖),那么你永远不会调用 Equals。这就是为什么你应该始终实现这两个函数的部分原因 - 如果你想在散列集合中使用你的对象,你应该重写这两个函数(比调用 base.GetHashCode() 更有意义)。

    如果您正在实现一个类,您应该实现一个 GetHashCode 例程,该例程为 Equal 的项目返回相同的哈希码。理想情况下,您希望尽可能为不相等的项目返回不同的哈希码,因为这将使您的字典查找速度更快。

    您还应该以正确检查相等实例的方式实现 Equals。

    类(引用类型)的默认实现只是比较引用本身。默认情况下,具有完全相同值的两个实例在 Equals 上返回 false(因为它们具有不同的引用)。默认情况下,多个实例也总是返回不同的哈希码。

    【讨论】:

      【解决方案2】:

      字典是一个哈希表。如果两个对象产生相同的哈希值,它只会调用 Equals(object obj)。为您的对象提供良好的哈希函数以避免调用 Equals()。

      请记住,哈希部分的复杂度为 O(1),而搜索部分的复杂度在最坏情况下为 O(n),在平均情况下为 O(n/2)。您应该避免生成相同哈希值的对象,否则会线性搜索此对象

      【讨论】:

        【解决方案3】:

        假设您已将自定义引用类型定义为键,您必须:

        1. 始终将相同的对象实例作为键传递到字典中,或者
        2. 实现一个 GetHashCode(),即使对于不同的实例也总是返回相同的值,并且 Equals() 方法可以比较不同的实例。

        base.GetHashCode() 方法基于对象的实例标识构建哈希,因此当您将类型的不同实例作为键传递时,不能使用该方法。

        为您的哈希返回 0 始终有效的原因是 Dictionary 类首先使用哈希码查找您的密钥所属的存储桶,然后才使用 Equals() 方法来区分实例。如果您打算将自定义类型用作字典键,则不应将 0 作为哈希码返回,因为这会有效地将字典退化为具有 O(n) 查找性能而不是 O(1) 的列表。

        您可能还想考虑实现 IComparable 和 IEquatable。

        查看以下问题了解更多详情:

        Using an object as a generic Dictionary key

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-14
          • 1970-01-01
          • 2011-04-11
          • 1970-01-01
          • 2011-01-16
          相关资源
          最近更新 更多