GetHashCode 是否保证在对象的生命周期内相同? [英] Is GetHashCode guaranteed to be the same for the lifetime of an object?

查看:33
本文介绍了GetHashCode 是否保证在对象的生命周期内相同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我讨厌打败一个 .在@eric-lippert 的博客,他说:

I hate to beat a dead horse. In @eric-lippert's blog, he states:

一个对象的哈希值在其整个生命周期内都是相同的

the hash value of an object is the same for its entire lifetime

然后跟进:

然而,这只是一个理想情况指南

However, this is only an ideal-situation guideline

所以,我的问题是这个.

So, my question is this.

对于 POCO(没有覆盖)或框架(如 FileInfoProcess)对象,是 GetHashCode() 方法在其生命周期内保证相同?

For a POCO (nothing overriden) or a framework (like FileInfo or Process) object, is the return value of the GetHashCode() method guaranteed to be the same during its lifetime?

附言我说的是预先分配的对象.var foo = new Bar();foo.GetHashCode() 总是返回相同的值.

P.S. I am talking about pre-allocated objects. var foo = new Bar(); Will foo.GetHashCode() always return the same value.

推荐答案

如果你查看 MSDN 文档 您会发现以下关于 GetHashCode 方法的默认行为的说明:

If you look at the MSDN documentation you will find the following remarks about the default behavior of the GetHashCode method:

如果未覆盖 GetHashCode,则引用类型的哈希码为通过调用基类的 Object.GetHashCode 方法计算,它根据对象的引用计算哈希码;更多信息,请参见 RuntimeHelpers.GetHashCode.换句话说,两个ReferenceEquals 方法为其返回 true 的对象具有相同的哈希码.如果值类型不覆盖 GetHashCode,则基类的 ValueType.GetHashCode 方法使用反射来根据类型字段的值计算哈希码.在换句话说,字段具有相等值的值类型具有相等哈希码

If GetHashCode is not overridden, hash codes for reference types are computed by calling the Object.GetHashCode method of the base class, which computes a hash code based on an object's reference; for more information, see RuntimeHelpers.GetHashCode. In other words, two objects for which the ReferenceEquals method returns true have identical hash codes. If value types do not override GetHashCode, the ValueType.GetHashCode method of the base class uses reflection to compute the hash code based on the values of the type's fields. In other words, value types whose fields have equal values have equal hash codes

根据我的理解,我们可以假设:

Based on my understanding we can assume that:

  • 对于引用类型(不覆盖 Object.GetHashCode)给定实例的哈希码的值保证是实例的整个生命周期都相同(因为内存对象存储的地址在其期间不会改变终生)
  • 对于值类型(不覆盖 Object.GetHashCode),它取决于:如果值类型是不可变的,那么哈希码不会在其生命周期中发生变化.如果,否则,其字段的值可以在创建后更改,那么它的哈希码也会更改.请注意,值类型通常是不可变的.

重要修改

正如上面的一条评论所指出的,.NET 垃圾收集器可以决定在对象生命周期内移动对象在内存中的物理位置,换句话说,对象可以在托管内存中重定位".

As pointed out in one comment above the .NET garbage collector can decide to move the physical location of an object in memory during the object lifetime, in other words an object can be "relocated" inside the managed memory.

这是有道理的,因为垃圾收集器负责管理创建对象时分配的内存.

This makes sense because the garbage collector is in charge of managing the memory allocated when objects are created.

经过一些搜索并根据 thisstackoverflow 问题(阅读用户@supercat 提供的评论)这个重定位似乎不会改变对象实例在其生命周期内的哈希码,因为哈希码计算一次(第一次请求它的值)并且计算出的值被保存并稍后重用(当再次请求哈希码值).

After some searches and according to this stackoverflow question (read the comments provided by the user @supercat) it seems that this relocation does not change the hash code of an object instance during its lifetime, because the hash code is calculated once (the first time that it's value is requested) and the computed value is saved and reused later (when the hash code value is requested again).

总而言之,根据我的理解,您唯一可以假设的是给定指向内存中同一个对象的两个引用,它们的哈希码将始终相同.换句话说,如果 Object.ReferenceEquals(a, b) 则 a.GetHashCode() == b.GetHashCode().此外,似乎给定一个对象实例,它的哈希码将在其整个生命周期内保持不变,即使垃圾收集器更改了对象的物理内存地址.

To summarize, based on in my understanding, the only thing you can assume is that given two references pointing to the same object in memory the hash codes of them will always be identical. In other words if Object.ReferenceEquals(a, b) then a.GetHashCode() == b.GetHashCode(). Furthermore it seems that given an object instance its hash code will stay the same for its entire lifetime, even if the physical memory address of the object is changed by the garbage collector.

关于哈希码使用的旁注

请务必记住,.NET 框架中引入哈希码的唯一目的是处理哈希表数据结构.

It is important to always remember that the hash code has been introduced in the .NET framework at the sole purpose of handling the hash table data structure.

为了确定用于给定value的bucket,取相应的key并计算其哈希码(准确地说,bucket索引是通过对 GetHashCode 调用返回的值应用一些规范化获得的,但细节对于本讨论并不重要).换句话说,哈希表的 .NET 实现中使用的哈希函数是基于键的哈希码的计算.

In order to determine the bucket to be used for a given value, the corresponding key is taken and its hash code is computed (to be precise, the bucket index is obtained by applying some normalizations on the value returned by the GetHashCode call, but the details are not important for this discussion). Put another way, the hash function used in the .NET implementation of hash tables is based on the computation of the hash code of the key.

这意味着哈希码的唯一安全用法是平衡哈希表,正如 Eric Lippert 指出的那样 此处,所以不要为了任何其他目的编写依赖于哈希码值的代码.

This means that the only safe usage for an hash code is balancing an hash table, as pointed out by Eric Lippert here, so don't write code which depends on hash codes values for any other purpose.

这篇关于GetHashCode 是否保证在对象的生命周期内相同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆