我们什么时候为Dictionary做GetHashCode()?

时间:2009-09-10 19:55:17

标签: c# .net

我已将Dictionary(TKey,TValue)用于多种用途。但我没有遇到任何实现GetHashCode()的场景,我认为这是因为我的键是主要类型,如int和string。 我很想知道场景(真实世界的例子),当一个人应该使用自定义对象的键,从而实现方法GetHashCode()Equals()等。

而且,使用自定义对象作为密钥是否需要实现这些功能?

4 个答案:

答案 0 :(得分:13)

每当默认Object.Equals(参考相等测试)不够时,您应该覆盖EqualsGetHashCode。例如,当您的密钥类型是自定义类型并且您希望两个密钥被认为相等时,即使在它们不是自定义类型的同一实例的情况下,也会发生这种情况。

例如,如果您的密钥就像

一样简单
class Point {
    public int X { get; set; }
    public int Y { get; set; }
}

如果Point s相等并且X s相等,则您希望两个Y两个被视为相等,那么您需要覆盖Equals和{ {1}}。

答案 1 :(得分:12)

只是要说清楚:Dictionary<TKey, TValue>GetHashCode()有一个重要的事情:Dictionary使用GetHashCode来确定两个键是否相等,即如果<TKey>是自定义类型,你应该关心谨慎实施GetHashCode()。正如Andrew Hare指出这很容易,如果你有一个简单的类型,可以明确地识别你的自定义对象。如果你有一个组合标识符,它会变得更复杂。

例如,将复数视为TKey。复数由它的真实及其虚部决定。两者都是简单类型,例如double。但是你如何确定两个复数是否相等?您为自定义复杂类型实现GetHashode(),并将两个识别部分组合在一起。

您可以进一步阅读后者here

<强>更新

根据Ergwun的评论,我检查了Dictionary<TKey, TValue>.Add的行为,特别尊重TKey Equals(object)GetHashCode()的实施情况。一世 我必须承认我对结果感到非常惊讶。

给定k1类型k2TKey的两个对象,v1类型的两个任意对象v2TValue,并为空类型为d的字典Dictionary<TKey, TValue>,这是首先将v1添加到k1 dv2k2添加密钥{{1}第二个(取决于TKey.Equals(object)TKey.GetHashCode()的实现):

k1.Equals(k2)   k1.GetHashCode() == k2.GetHashCode()   d.Add(k2, v2)
false           false                                  ok
false           true                                   ok
true            false                                  ok
true            true                                   System.ArgumentException

结论:我错了,因为我最初认为第二种情况(Equals返回false,但两个关键对象都有相同的哈希码)会引发ArgumentException。但是,由于第三种情况以某种方式显示字典确实使用GetHashCode()。无论如何,两个相同类型且相同的对象必须返回相同的哈希码以确保实例Dictionary<TKey, TValue>正常工作,这似乎是一个好建议。

答案 2 :(得分:2)

一个例子是当你需要创建一个复合键(这是一个由多个数据组成的键)。该组合键将是一个需要覆盖这些方法的自定义类型。

例如,假设您有一个内存中的地址记录缓存,并且您想检查地址是否在缓存中以节省昂贵的数据库访问以检索它。我们还要说地址在 street 1 邮政编码字段方面是唯一的。您可以使用以下内容实现缓存:

class AddressCacheKey
{
    public String StreetOne { get; set; }
    public String ZipCode { get; set; }

    // overrides for Equals and GetHashCode
}

static Dictionary<AddressCacheKey,Address> cache;

由于您的AddressCacheKey类型会覆盖EqualsGetHashCode方法,因此它们可能是字典中某个键的理想选择,您可以确定是否需要前往数据库,根据多个数据检索记录。

答案 3 :(得分:1)

这里有两个问题。

  1. 您何时需要实施 GetHashCode()
  2. 您是否会使用对象作为字典键。
  3. 让我们从1开始。如果你正在编写一个可能被其他人使用的类,那么当引用Equals()不够时,你将需要定义GetHashCode()和Equals()。如果您不打算在字典中使用它,并且它是为了您自己的用法,那么我认为没有理由跳过GetHashCode()等。

    对于2),您应该在需要从对象到其他类型的常量时间查找时使用对象。由于GetHashCode()返回一个数值,并且集合存储引用,因此在Int或字符串上使用Object没有任何代价(请记住字符串是一个对象)。