简体   繁体   English

在个人类上使用字典时,为什么不必覆盖GetHashCode?

[英]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!)). 如果使用值类型,则EqualsGetHashCode的默认实现是可以的( 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; 如果您使用的是引用类型,则EqualsGetHashCode的默认实现使用引用相等,这可能行不通; 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 . 如果没有,覆盖EqualsGetHashCode或implmenet IEqualityComparer<T>为你T

I'd still like to know how the magic works, though =P 我仍然想知道魔术是如何工作的,尽管= P

Every object has Equals and GetHashCode . 每个对象都有EqualsGetHashCode The default implementations are as follows: 默认实现如下:

  1. For value types, Equals is value equality. 对于值类型, Equals值相等。
  2. For reference types, Equals is reference equality. 对于引用类型, Equals引用相等。
  3. For value types, GetHashCode is based on the fields (again, not necessarily all of them!). 对于值类型, GetHashCode基于字段(同样,不一定是所有字段!)。
  4. For reference types, 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>仅使用EqualsGetHashCode 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. 如果覆盖EqualsGetHashCode则将使用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. 如果对相等性有不同的定义,则应重写EqualsGetHashCode以获得适当的行为。

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.

相关问题 我为什么不*覆盖GetHashCode()? - Why should I *not* override GetHashCode()? 为什么Hashtables和词典不使用Equals()方法而不是GetHashCode用于.NET中的键比较? - Why don't Hashtables and dictionaries use Equals() method instead of GetHashCode for keys comparision in .NET? 我编写的第一个应用程序崩溃了,我也不知道为什么 - The first app I have ever written crashes and I don't know why 何时重写GetHashCode()? - When to override GetHashCode()? 为什么我不能在EF4中的多对多实体上覆盖GetHashCode? - Why can't I override GetHashCode on a many-to-many entity in EF4? 在==运算符覆盖中使用GetHashCode - Using GetHashCode in == operator override 为什么不列出 <T> .GetHashCode和ObservableCollection <T> .GetHashCode评估他们的项目? - why don't List<T>.GetHashCode and ObservableCollection<T>.GetHashCode evaluate their items? 为什么在重载相等运算符时,您希望覆盖GetHashCode和Equals? - Why are you expected to override GetHashCode and Equals when overloading the equality operator? 为什么在重写 Equals 方法时重写 GetHashCode 很重要? - Why is it important to override GetHashCode when Equals method is overridden? 为什么我必须在不必使用关键字static时使用? - Why must I use keyword static when they don't have to?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM