为什么在个人类上使用字典时我不需要覆盖 GetHashCode?

发布于 2024-12-05 08:19:37 字数 279 浏览 1 评论 0原文

它似乎总是只是“工作”而无需做任何事情。

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

我从未重写过 GetHashCode 但我四处阅读,人们说你只需要在重写 Equals 并向您的应用程序提供自定义相等性检查,所以我想我没问题?

不过我还是想知道魔法是如何运作的=P

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. (also, does anyone know how Object.GetHashCode is implemented? I couldn't find it in the .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?

I'd still like to know how the magic works, though =P

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

季末如歌 2024-12-12 08:19:37

它似乎总是“工作”而无需执行任何操作。

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

如果您使用值类型,则 EqualsGetHashCode 的默认实现是可以的(Equals 检查字段是否相等,并且 >GetHashCode 基于字段(不一定是所有字段!))。如果您使用引用类型,则 EqualsGetHashCode 的默认实现使用引用相等,这可能会也可能不会。这取决于你在做什么。

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

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

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

这是一个您永远不需要知道、也永远不会依赖它的实现细节。你的情况随时可能发生变化。

我从未重写过 GetHashCode,但我四处阅读,人们说您只需要在重写 Equals 并向应用程序提供自定义相等性检查时才需要这样做,所以我想我没问题?

好吧,默认平等适合你吗?如果没有,请覆盖 EqualsGetHashCode 或为您的 T 实现 IEqualityComparer

不过我还是想知道魔法是如何运作的=P

每个对象都有 EqualsGetHashCode。默认实现如下:

  1. 对于值类型,Equals 表示值相等。
  2. 对于引用类型,Equals 是引用相等。
  3. 对于值类型,GetHashCode 基于字段(同样,不一定是所有字段!)。
  4. 对于引用类型,GetHashCode 基于引用。

如果您使用 Dictionary 构造函数的重载,而该构造函数不为 T 采用 IEqualityComparer,则它将使用 EqualityComparer< ;T>.默认。此 IEqualityComparer 仅使用 EqualsGetHashCode。因此,如果您没有覆盖它们,您将获得上面定义的实现。如果您覆盖 EqualsGetHashCode,那么这就是 EqualityComparer.Default 将使用的内容。

否则,将 IEqualityComparer 的自定义实现传递给 Dictionary 的构造函数。

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!)). If you're using reference types, the default implementation of Equals and GetHashCode use reference equality, which may or may not be okay; 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.

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)

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?

Well, is default equality okay for you? If not, override Equals and GetHashCode or implmenet IEqualityComparer<T> for your T.

I'd still like to know how the magic works, though =P

Every object has Equals and GetHashCode. The default implementations are as follows:

  1. For value types, Equals is value equality.
  2. For reference types, Equals is reference equality.
  3. For value types, GetHashCode is based on the fields (again, not necessarily all of them!).
  4. For reference types, GetHashCode is based on the reference.

If you use a overload of Dictionary constructor that doesn't take a IEqualityComparer<T> for your T, it will use EqualityComparer<T>.Default. This IEqualityComparer<T> just uses Equals and 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.

Otherwise, pass a custom implementation of IEqualityComparer<T> to the constructor for Dictionary.

爱给你人给你 2024-12-12 08:19:37

您是否使用自定义类作为键或值?如果您仅将它们用于值,那么它们的 GetHashCode 并不重要。

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

Object.GetHashCode 的文档非常清晰

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

Are you using your custom classes as keys or values? If you are using them only for values, then their GetHashCode doesn't matter.

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. 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).

The documentation for Object.GetHashCode is quite clear:

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.

暖树树初阳… 2024-12-12 08:19:37

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

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

仅当您想按值比较时才需要覆盖它们 - 如果您希望具有相同属性的不同实例比较相等。

Object's implementations of Equals() and GetHashCode() (which you're inheriting) compare by reference.
Object.GetHashCode is implemented in native code; you can see it in the SSCLI (Rotor).

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.

热风软妹 2024-12-12 08:19:37

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

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 以获得适当的行为。

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.

孤者何惧 2024-12-12 08:19:37

哈希码用于优化哈希表(字典)中的查找性能。虽然哈希码的目标是尽可能减少对象实例之间的冲突,但它们不能保证是唯一的。目标应该是在给定这些对象的一组典型类型的 int 范围之间进行平均分配。

哈希表的工作方式是每个对象实现一个函数来计算哈希码,希望尽可能分布在 int 范围内。两个不同的对象可以产生相同的哈希码,但给定数据的对象实例应该始终产生相同的哈希码。因此,它们不是唯一的,不应该用于平等。哈希表分配一个大小为 n(比 int 范围小得多)的数组,当将对象添加到哈希表时,它会调用 GetHashCode,然后根据分配的数组大小进行 mod'd (%)。对于表中的冲突,通常会链接对象列表。由于计算哈希码应该非常快,因此查找速度很快 - 跳转到数组偏移量并遍历链。数组越大(内存越大),冲突越少,查找速度越快。

对象 GetHashCode 不可能生成良好的哈希码,因为根据定义,它对继承自它的具体对象一无所知。这就是为什么如果您有需要放置在字典中的自定义对象并且您想要优化查找(控制创建具有最小冲突的均匀分布),您应该重写 GetHashCode。

如果您需要比较两个项目,请覆盖 equals。如果您需要对象可排序(这是排序列表所需要的),则重写 IComparable。

希望这有助于解释其中的差异。

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.

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. 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. 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. 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.

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.

Hope that helps explain the difference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文