为什么不';在个人类上使用Dictionaries时,我不需要覆盖GetHashCode
本文关键字:Dictionaries 不需要 GetHashCode 覆盖 人类 为什么不 | 更新日期: 2023-09-27 18:09:09
它似乎总是"工作"而不需要做任何事情。
我唯一能想到的是,每个类都有一个Object.GetHashCode
使用的隐藏类型的静态标识符。(还有,有人知道Object.GetHashCode是如何实现的吗?我在.NET Reflector中找不到它(
我从未重写过GetHashCode
,但我四处阅读,人们说你只需要在重写Equals并为你的应用程序提供自定义相等性检查时才需要重写,所以我想我还好吧?
尽管=p
它似乎总是"工作"而不需要做任何事情。
您没有告诉我们您的键是使用值类型还是引用类型。
如果使用值类型,则Equals
和GetHashCode
的默认实现是可以的(Equals
检查字段是否相等,GetHashCode
基于字段(不一定是所有字段!((。如果您使用引用类型,Equals
和GetHashCode
的默认实现使用引用相等,这可能没问题,也可能没问题;这取决于你在做什么。
我唯一能想到的是,每个类都有一个
Object.GetHashCode
使用的隐藏类型的静态标识符。
没有。默认值是基于值类型的字段和引用类型的引用的哈希代码。
(还有,有人知道Object.GetHashCode是如何实现的吗?我在.NET Reflector中找不到它(
这是一个实现细节,你永远不应该知道,也永远不应该依赖它。它随时可能对你产生影响。
我从来没有重写过GetHashCode,但我四处阅读,人们说你只需要在重写Equals并为你的应用程序提供自定义相等性检查时才需要重写,所以我想我没事吧?
默认相等对你来说可以吗?如果没有,请覆盖Equals
和GetHashCode
,或为您的T
执行IEqualityComparer<T>
。
我仍然想知道魔法是如何运作的,尽管=p
每个对象都有Equals
和GetHashCode
。默认实现如下:
- 对于值类型,
Equals
是值相等 - 对于引用类型,
Equals
是引用相等 - 对于值类型,
GetHashCode
基于字段(同样,不一定是所有字段!( - 对于引用类型,
GetHashCode
基于引用
如果您使用Dictionary
构造函数的重载,而该重载不将IEqualityComparer<T>
作为T
,则它将使用EqualityComparer<T>.Default
。这个IEqualityComparer<T>
只使用了Equals
和GetHashCode
。因此,如果您还没有覆盖它们,那么您将获得上面定义的实现。如果覆盖Equals
和GetHashCode
,则这就是EqualityComparer<T>.Default
将使用的内容。
否则,将IEqualityComparer<T>
的自定义实现传递给Dictionary
的构造函数。
您是否将自定义类用作键或值?如果您仅将它们用于值,则它们的GetHashCode
无关紧要。
如果将它们用作密钥,则哈希的质量会影响性能。Dictionary
存储每个哈希代码的元素列表,因为哈希代码不需要是唯一的。在最坏的情况下,如果所有键最终都具有相同的哈希代码,那么字典的查找时间将类似于列表O(n(,而不是哈希表O(1(。
Object.GetHashCode的文档非常清楚:
GetHashCode方法的默认实现不能保证不同对象的唯一返回值。。。因此,此方法的默认实现不能用作哈希目的的唯一对象标识符。
Object
对Equals()
和GetHashCode()
(您正在继承(的实现通过引用进行比较
CCD_ 37以本机代码实现;您可以在SSCLI(转子(中看到它。
一个类的两个不同实例(通常(将具有不同的哈希代码,即使它们的属性相等。
如果要按值进行比较,只需要覆盖它们–如果要将具有相同属性的不同实例进行相等比较。
它实际上取决于您对Equality的定义。
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
&CCD_ 39以获得适当的行为。
哈希代码用于优化哈希表(字典(中的查找性能。虽然散列码的目标是在对象实例之间尽可能少地发生冲突,但它们不能保证是唯一的。目标应该是在给定这些对象的一组典型类型的情况下,在int范围内均匀分布。
哈希表的工作方式是每个对象实现一个函数来计算哈希代码,希望它尽可能分布在int范围内。两个不同的对象可以生成相同的哈希代码,但给定对象数据的对象实例应该始终生成相同的散列代码。因此,它们不是唯一的,不应用于平等。哈希表分配一个大小为n(远小于int范围(的数组,当向哈希表中添加对象时,它会调用GetHashCode,然后根据分配的数组大小对其进行mod'd(%(。对于表中的冲突,通常会链接一个对象列表。由于计算散列码应该非常快,所以查找是快速的——跳到数组偏移量并遍历链。数组越大(内存越多(,冲突就越少,查找也就越快。
对象GetHashCode不可能生成一个好的哈希代码,因为根据定义,它对从中继承的具体对象一无所知。这就是为什么如果你有需要放入字典中的自定义对象,并且你想优化查找(控制创建具有最小冲突的均匀分布(,你应该重写GetHashCode。
如果需要比较两个项目,则重写equals。如果您需要对象是可排序的(排序列表需要(,那么覆盖IComparable。
希望这有助于解释差异。