C# 我们什么时候为字典执行GetHashCode()?

C# 我们什么时候为字典执行GetHashCode()?,c#,.net,C#,.net,我使用字典(TKey,TValue)有很多用途。但是我没有遇到任何实现GetHashCode()的场景,我相信这是因为我的键是int和string等主要类型。 我很想知道在什么情况下(真实世界的例子),人们应该使用自定义对象作为键,从而实现GetHashCode()Equals()等方法 而且,使用自定义对象作为密钥是否需要实现这些功能?一个示例是,当您需要创建复合密钥(即包含多个数据段的密钥)时。该复合键将是需要重写这些方法的自定义类型 例如,假设您有一个内存中的地址记录缓存,您想检查一个地址

我使用字典(TKey,TValue)有很多用途。但是我没有遇到任何实现GetHashCode()的场景,我相信这是因为我的键是int和string等主要类型。 我很想知道在什么情况下(真实世界的例子),人们应该使用自定义对象作为键,从而实现GetHashCode()Equals()等方法


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

一个示例是,当您需要创建复合密钥(即包含多个数据段的密钥)时。该复合键将是需要重写这些方法的自定义类型

例如,假设您有一个内存中的地址记录缓存,您想检查一个地址是否在缓存中,以节省昂贵的数据库检索行程。也可以说,地址在street 1和zip code字段方面是唯一的。您可以使用以下内容实现缓存:

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

    // overrides for Equals and GetHashCode
}

静态字典缓存;

由于您的
AddressCacheKey
类型覆盖了
Equals
GetHashCode
方法,因此它们是字典中键的一个很好的候选者,您可以确定是否需要访问数据库以基于多个数据段检索记录。

当默认值(参考相等性测试)不满足要求时,覆盖
Equals
GetHashCode
。例如,如果密钥的类型是自定义类型,并且希望两个密钥被视为相等,即使它们不是自定义类型的同一实例,也会发生这种情况

例如,如果您的密钥与

class Point {
    public int X { get; set; }
    public int Y { get; set; }
}

你想要两个
s如果他们的
X
s相等,他们的
Y
s相等,那么你需要覆盖
Equals
GetHashCode
这里有两个问题

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


    对于2),只要需要从对象到其他类型进行固定时间的查找,就应该使用对象。由于GetHashCode()返回一个数值,集合存储引用,因此在Int或字符串上使用对象(请记住字符串是一个对象)不会受到任何惩罚。

    只需澄清一点:关于
    字典
    GetHashCode()
    :Dictionary使用GetHashCode来确定两个键是否相等,即如果
    是自定义类型,您应该小心地实现
    GetHashCode()
    。正如Andrew Hare指出的,如果您有一个明确标识自定义对象的简单类型,那么这很容易。如果您有一个组合标识符,它会变得更复杂一些

    例如,把复数看作<代码> TKey < /代码>。复数由其实部和虚部决定。两者都是简单类型,例如
    double
    。但是,如果两个复数相等,您将如何识别?您可以为自定义复杂类型实现
    GetHashCode()
    ,并将这两个标识部分结合起来

    你可以进一步阅读后者

    更新

    根据Ergwun的评论,我检查了
    字典的行为。添加
    ,特别是
    TKey
    实现的
    Equals(object)
    GetHashCode()
    。我 我必须承认,我对结果感到相当惊讶

    给定类型为
    TKey
    的两个对象
    k1
    k2
    ,类型为
    TValue
    的两个任意对象
    v1
    v2
    ,以及类型为
    dictionary
    的空字典
    d
    ,这是在将带有键
    k1的
    v1
    添加到
    d
    和带有键
    k2的
    v2
    时发生的情况(取决于
    TKey.Equals(object)
    TKey.GetHashCode()
    的实现):


    结论:我错了,因为我最初认为第二种情况(其中
    Equals
    返回
    false
    ,但两个关键对象都有相同的哈希代码)会引发
    ArgumentException
    。但正如第三个案例所示,字典在某种程度上确实使用了
    GetHashCode()
    。无论如何,这似乎是一个很好的建议,即两个类型相同且相等的对象必须返回相同的哈希代码,以确保实例
    Dictionary
    正常工作。

    -1 Dictionary不使用
    GetHashCode()
    来确定两个键是否相等。也就是说,字典可以包含其键具有相同哈希代码的单独条目。字典可能效率较低,但仍能工作。是的,您应该确保相等的对象返回相同的哈希代码(请参阅)。对于字典,如果1)我就地编辑对象并将
    point.X
    交换为
    point.Y
    ,那么Equals和GetHashCode需要是什么?是否必须删除该值,并将其重新添加到字典中?读取的可能重复项这不是Int32 A对象,因为它派生自System.object派生的System.ValueType。读取该值
    class Point {
        public int X { get; set; }
        public int Y { get; set; }
    }
    
    k1.Equals(k2)   k1.GetHashCode() == k2.GetHashCode()   d.Add(k2, v2)
    false           false                                  ok
    false           true                                   ok
    true            false                                  ok
    true            true                                   System.ArgumentException