C# 为什么不';在个人类上使用字典时,我是否必须重写GetHashCode?

C# 为什么不';在个人类上使用字典时,我是否必须重写GetHashCode?,c#,hash,dictionary,hashtable,C#,Hash,Dictionary,Hashtable,它似乎总是“工作”而不必做任何事情 我唯一能想到的是,每个类都有一个隐藏的静态标识符,Object.GetHashCode使用它。(还有,有人知道Object.GetHashCode是如何实现的吗?我在.NET Reflector中找不到它) 我从来没有重写过GetHashCode,但我一直在阅读,人们说,只有在重写Equals并为应用程序提供自定义的相等检查时,才需要这样做,所以我想我没事吧 我仍然想知道这个魔法是如何工作的,不过,=pObject的Equals()和GetHashCode()

它似乎总是“工作”而不必做任何事情

我唯一能想到的是,每个类都有一个隐藏的静态标识符,
Object.GetHashCode
使用它。(还有,有人知道Object.GetHashCode是如何实现的吗?我在.NET Reflector中找不到它)

我从来没有重写过
GetHashCode
,但我一直在阅读,人们说,只有在重写Equals并为应用程序提供自定义的相等检查时,才需要这样做,所以我想我没事吧


我仍然想知道这个魔法是如何工作的,不过,=p

Object
Equals()
GetHashCode()
(您继承的)的实现通过引用进行比较。
Object.GetHashCode
在本机代码中实现;您可以在SSCLI(转子)中看到它

一个类的两个不同实例(通常)具有不同的哈希代码,即使它们的属性相等


如果要按值进行比较,您只需覆盖它们—如果要将具有相同属性的不同实例进行相等比较。

这实际上取决于您对相等的定义

class Person
{
    public string Name {get; set;}
}

void Test()
{
    var joe1 = new Person {Name="Joe"};
    var joe2 = new Person {Name="Joe"};

    Assert.AreNotEqual(joe1, joe2);
}

如果对相等有不同的定义,则应重写
Equals
&
GetHashCode
,以获得适当的行为。

是否将自定义类用作键或值?如果只对值使用它们,那么它们的
GetHashCode
就无关紧要了

如果将它们用作键,则哈希的质量会影响性能。
字典
存储每个哈希代码的元素列表,因为哈希代码不需要是唯一的。在最坏的情况下,如果所有键都具有相同的哈希代码,那么字典的查找时间将类似于列表O(n),而不是哈希表O(1)

Object.GetHashCode的文档非常简单:

GetHashCode方法的默认实现不保证不同对象的唯一返回值。。。因此,此方法的默认实现不得用作哈希目的的唯一对象标识符

它似乎总是“工作”而不必做任何事情

您没有告诉我们您的键使用的是值类型还是引用类型

如果您使用的是值类型,
Equals
GetHashCode
的默认实现是正常的(
Equals
检查字段是否相等,
GetHashCode
基于字段(不一定是所有字段!))。如果您使用的是引用类型,
Equals
GetHashCode
的默认实现使用引用相等,这可能没问题,也可能没问题;这取决于你在做什么

我唯一能想到的是,每个类都有一个隐藏的静态标识符,
Object.GetHashCode
使用它

否。默认值是基于值类型字段和引用类型引用的哈希代码

(还有,有人知道Object.GetHashCode是如何实现的吗?我在.NET Reflector中找不到它)

这是一个实现细节,您永远不应该需要知道,也永远不应该依赖它。你随时都可能改变

我从来没有重写过GetHashCode,但我一直在阅读,人们说,只有在重写Equals并为应用程序提供自定义的相等检查时,才需要重写GetHashCode,所以我想我没事吧

那么,默认平等对你合适吗?如果不是,则为您的
T
重写
equalitycomparer
GetHashCode
或执行
IEqualityComparer

不过,我还是想知道魔法是如何发挥作用的

每个对象都有
等于
GetHashCode
。默认实现如下所示:

  • 对于值类型,
    Equals
    表示值相等
  • 对于引用类型,
    Equals
    表示引用相等
  • 对于值类型,
    GetHashCode
    基于字段(同样,不一定是所有字段!)
  • 对于引用类型,
    GetHashCode
    基于引用
  • 如果您使用的
    Dictionary
    构造函数的重载没有为
    t
    使用
    IEqualityComparer
    ,它将使用
    EqualityComparer.Default
    。这个
    IEqualityComparer
    只使用
    等于
    GetHashCode
    。因此,如果您没有覆盖它们,那么您将得到上面定义的实现。如果覆盖
    Equals
    GetHashCode
    则这就是
    EqualityComparer。默认值将使用


    否则,将
    IEqualityComparer
    的自定义实现传递给
    Dictionary
    的构造函数哈希代码用于优化哈希表(字典)中的查找性能。虽然哈希代码的目标是尽可能减少对象实例之间的冲突,但不能保证它们是唯一的。目标应该是在给定一组典型类型的对象的int范围内均匀分布

    哈希表的工作方式是每个对象实现一个函数来计算哈希代码,希望尽可能分布在int范围内。两个不同的对象可以生成相同的哈希代码,但给定对象数据的对象实例应始终生成相同的哈希代码。因此,它们不是唯一的,不应用于平等。哈希表分配一个大小为n(远小于int范围)的数组,当一个对象被添加到哈希表中时,它调用GetHashCode,然后根据分配的数组大小调整它的mod'd(%)。对于表中的碰撞,通常会链接对象列表。由于计算哈希代码应该非常快,所以查找是快速跳转到数组