[英]Why don't I ever have to override GetHashCode when using Dictionaries on personal classes?
It always seems to just "work" without ever having to do anything. 它似乎总是“工作”而无需做任何事情。
The only thing I can think of is that each class has a hidden sort of static identifier that Object.GetHashCode
uses. 我唯一能想到的是每个类都有一个Object.GetHashCode
使用的隐藏的静态标识符。 (also, does anyone know how Object.GetHashCode is implemented? I couldn't find it in the .NET Reflector) (同样,有人知道Object.GetHashCode是如何实现的吗?我在.NET Reflector中找不到它)
I have never overridden GetHashCode
but I was reading around and people say you only need to when overriding Equals and providing custom equality checking to your application so I guess I'm fine? 我从未覆盖过GetHashCode
但我一直在阅读,人们说,您只需要在覆盖Equals并为您的应用程序提供自定义相等性检查时才这样做,所以我想我很好吗?
I'd still like to know how the magic works, though =P 我仍然想知道魔术是如何工作的,尽管= P
It always seems to just "work" without ever having to do anything. 它似乎总是“工作”而无需做任何事情。
You didn't tell us if you're using value types or reference types for your keys. 您没有告诉我们您是在使用键的值类型还是引用类型。
If you're using value types, the default implementation of Equals
and GetHashCode
are okay ( Equals
checks if the fields are equals, and GetHashCode
is based on the fields (not necessarily all of them!)). 如果使用值类型,则Equals
和GetHashCode
的默认实现是可以的( Equals
检查字段是否相等,而GetHashCode
基于字段(不一定是全部!)。 If you're using reference types, the default implementation of Equals
and GetHashCode
use reference equality, which may or may not be okay; 如果您使用的是引用类型,则Equals
和GetHashCode
的默认实现使用引用相等,这可能行不通; it depends on what you're doing. 这取决于你在做什么。
The only thing I can think of is that each class has a hidden sort of static identifier that
Object.GetHashCode
uses. 我唯一能想到的是每个类都有一个Object.GetHashCode
使用的隐藏的静态标识符。
No. The default is a hash code based on the fields for a value type, and the reference for a reference type. 否。默认值为基于值类型的字段和引用类型的引用的哈希码。
(also, does anyone know how Object.GetHashCode is implemented? I couldn't find it in the .NET Reflector) (同样,有人知道Object.GetHashCode是如何实现的吗?我在.NET Reflector中找不到它)
It's an implementation detail that you should never ever need to know, and never ever rely on it. 这是一个实现细节,您永远都不需要知道,也永远不要依赖它。 It could change on you at any moment. 它随时可能改变。
I have never overridden GetHashCode but I was reading around and people say you only need to when overriding Equals and providing custom equality checking to your application so I guess I'm fine? 我从未覆盖过GetHashCode,但我一直在阅读,人们说,您只需要在覆盖Equals并为您的应用程序提供自定义相等性检查时才这样做,所以我想我很好吗?
Well, is default equality okay for you? 好吧,默认相等对您还好吗? If not, override Equals
and GetHashCode
or implmenet IEqualityComparer<T>
for your T
. 如果没有,覆盖Equals
和GetHashCode
或implmenet IEqualityComparer<T>
为你T
。
I'd still like to know how the magic works, though =P 我仍然想知道魔术是如何工作的,尽管= P
Every object has Equals
and GetHashCode
. 每个对象都有Equals
和GetHashCode
。 The default implementations are as follows: 默认实现如下:
Equals
is value equality. 对于值类型, Equals
值相等。 Equals
is reference equality. 对于引用类型, Equals
引用相等。 GetHashCode
is based on the fields (again, not necessarily all of them!). 对于值类型, GetHashCode
基于字段(同样,不一定是所有字段!)。 GetHashCode
is based on the reference. 对于引用类型, GetHashCode
基于引用。 If you use a overload of Dictionary
constructor that doesn't take a IEqualityComparer<T>
for your T
, it will use EqualityComparer<T>.Default
. 如果您使用的Dictionary
构造函数的重载没有为您的T
携带IEqualityComparer<T>
,则它将使用EqualityComparer<T>.Default
。 This IEqualityComparer<T>
just uses Equals
and GetHashCode
. IEqualityComparer<T>
仅使用Equals
和GetHashCode
。 So, if you haven't overridden them, you get the implementations as defined above. 因此,如果您没有覆盖它们,则可以得到上面定义的实现。 If you override Equals
and GetHashCode
then this is what EqualityComparer<T>.Default
will use. 如果覆盖Equals
和GetHashCode
则将使用EqualityComparer<T>.Default
。
Otherwise, pass a custom implementation of IEqualityComparer<T>
to the constructor for Dictionary
. 否则,将IEqualityComparer<T>
的自定义实现传递给Dictionary
的构造函数。
Are you using your custom classes as keys or values? 您是否将自定义类用作键或值? If you are using them only for values, then their GetHashCode
doesn't matter. 如果仅将它们用于值,则它们的GetHashCode
无关紧要。
If you are using them as keys, then the quality of the hash affects performance. 如果将它们用作键,则哈希的质量会影响性能。 The Dictionary
stores a list of elements for each hash code, since the hash codes don't need to be unique. 该Dictionary
存储每个哈希代码元素的列表,因为散列码不必是唯一的。 In the worst case scenario, if all of your keys end up having the same hash code, then the lookup time for the dictionary will like a list, O(n), instead of like a hash table, O(1). 在最坏的情况下,如果所有键最终都具有相同的哈希码,则字典的查找时间将像列表O(n),而不像哈希表O(1)。
The documentation for Object.GetHashCode is quite clear : Object.GetHashCode的文档非常清楚 :
The default implementation of the GetHashCode method does not guarantee unique return values for different objects... Consequently, the default implementation of this method must not be used as a unique object identifier for hashing purposes. GetHashCode方法的默认实现不能保证不同对象的唯一返回值...因此,不得将此方法的默认实现用作哈希目的的唯一对象标识符。
Object
's implementations of Equals()
and GetHashCode()
(which you're inheriting) compare by reference. Equals()
和GetHashCode()
(您正在继承)的Object
的实现通过引用进行比较。
Object.GetHashCode
is implemented in native code; Object.GetHashCode
是用本机代码实现的; you can see it in the SSCLI (Rotor). 您可以在SSCLI(转子)中看到它。
Two different instances of a class will (usually) have different hashcodes, even if their properties are equal. 一个类的两个不同实例通常将具有不同的哈希码,即使它们的属性相等。
You only need to override them if you want to compare by value – if you want to different instances with the same properties to compare equal. 仅当要按值比较时才需要覆盖它们–如果要对具有相同属性的不同实例进行相等比较。
It really depends on your definition of 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);
}
If you have a different definition for equality, you should override Equals
& GetHashCode
to get the appropriate behavior. 如果对相等性有不同的定义,则应重写Equals
和GetHashCode
以获得适当的行为。
Hash codes are for optimizing lookup performance in hash tables (dictionaries). 哈希码用于优化哈希表(字典)中的查找性能。 While hash codes have a goal of colliding as little as possible between instances of objects they are not guaranteed to be unique. 尽管哈希码的目标是在对象实例之间尽可能减少冲突,但不能保证它们是唯一的。 The goal should be equal distribution among the int range given a set of typical types of those objects. 目标应该是在给定这些对象的一组典型类型的情况下,int范围之间的均等分布。
The way hash tables work is each object implements a function to compute a hash code hopefully as distributed as possible amongst the int range. 哈希表的工作方式是每个对象都实现一个函数,以计算希望在int范围内尽可能分布的哈希码。 Two different objects can produce the same hash code but an instance of an object given it's data should always product the same hash code. 两个不同的对象可以产生相同的哈希码,但给定对象实例的数据,则应始终产生相同的哈希码。 Therefore, they are not unique and should not be used for equality. 因此,它们不是唯一的,不应用于平等。 The hash table allocates an array of size n (much smaller than the int range) and when an object is added to the hash table, it calls GetHashCode and then it's mod'd (%) against the size of the array allocated. 哈希表分配一个大小为n(远小于int范围)的数组,当一个对象添加到哈希表中时,它将调用GetHashCode,然后根据分配的数组大小对其进行调制(%)。 For collisions in the table, typically a list of objects is chained. 对于表中的冲突,通常将对象列表链接在一起。 Since computing hash codes should be very fast, a lookup is fast - jump to the array offset and walk the chain. 由于哈希码的计算应该非常快,因此查找很快-跳转到数组偏移并遍历整个链。 The larger the array (more memory), the less collisions and the faster the lookup. 数组越大(内存越大),冲突越少并且查找速度越快。
Objects GetHashCode cannot possibly produce a good hash code because by definition it knows nothing about the concrete object that's inheriting from it. 对象GetHashCode可能无法生成良好的哈希码,因为根据定义,它对从其继承的具体对象一无所知。 That's why if you have custom objects that need to be placed in dictionaries and you want to optimize the lookups (control creating an even distribution with minimal collisions), you should override GetHashCode. 这就是为什么如果您有需要放置在字典中的自定义对象,并且想要优化查找(控制以最小的冲突创建均匀分布)的原因,则应该覆盖GetHashCode。
If you need to compare two items, then override equals. 如果需要比较两个项目,则覆盖等于。 If you need the object to be sortable (which is needed for sorted lists) then override IComparable. 如果您需要对象是可排序的(排序列表需要此对象),则重写IComparable。
Hope that helps explain the difference. 希望能帮助解释差异。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.