Object.GetHashCode() 的实现 [英] Implementation of Object.GetHashCode()

查看:60
本文介绍了Object.GetHashCode() 的实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读 Effective C# 和有一个关于 Object.GetHashCode() 的评论,我不明白:

I'm reading Effective C# and there is a comment about Object.GetHashCode() that I didn't understand:

Object.GetHashCode() 使用 System.Object 类中的内部字段来生成哈希值.创建的每个对象都会分配一个唯一的对象键,并在创建时存储为整数.
这些键从 1 开始并在每次获得任何类型的新对象时递增创建.对象标识字段在 System.Object 构造函数中设置,以后无法修改.Object.GetHashCode() 将此值作为给定对象的哈希码返回.

Object.GetHashCode() uses an internal field in the System.Object class to generate the hash value. Each object created is assigned a unique object key, stored as an integer, when it is created.
These keys start at 1 and increment every time a new object of any type gets created. The object identity field is set in the System.Object constructor and cannot be modified later. Object.GetHashCode() returns this value as the hash code for a given object.

我试图查看 Object.GetHashCode() 的文档,但没有找到任何相关信息.

I tried to look at the documentation of Object.GetHashCode() and didn't find any information about this.

我写了一段简单的代码来打印新生成的对象的哈希码:

I wrote the simple piece of code to print the hash code of newly generated objects:

using System;

namespace TestGetHashCode
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 100; i++)
            {
                object o = new object();
                Console.WriteLine(o.GetHashCode());
            }
        }
    }
}

打印的前几个数字是:

37121646,
45592480,
57352375,
2637164,
41014879,
3888474,
25209742,
26966483,
31884011

好像不太适合

这些键从 1 开始并在每次创建任何类型的新对象时递增...Object.GetHashCode() 返回此值

These keys start at 1 and increment every time a new object of any type gets created...Object.GetHashCode() returns this value

然后,为了在 System.Object 中找到这个内部字段",我尝试使用 ReSharper反编译源但我发现的代码是

Then, in order to find this "internal field in the System.Object" I tried using ReSharper decompiled sources but the code I found was

[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[__DynamicallyInvokable]
public virtual int GetHashCode()
{
  return RuntimeHelpers.GetHashCode(this);
}

再次使用反编译的源代码,我发现 RuntimeHelpers.GetHashCode 被实现为

and again using decompiled sources I found that RuntimeHelpers.GetHashCode was implemented as

[SecuritySafeCritical]
[__DynamicallyInvokable]
[MethodImpl(MethodImplOptions.InternalCall)]
public static int GetHashCode(object o);

遵循 MethodImpl 属性 似乎我无法查看实施,这对我来说是一个死胡同.

following the MethodImpl attribute it seems that I can't view the implementation and this is a dead end for me.

谁能解释一下作者的评论(第一句话)?

Can someone please explain the comment by the author (the first quote) ?

Object 类中的内部字段是什么以及它如何用于Object.GetHashCode() 的实现?

What is the internal field within the Object class and how it is used for the implementation of the Object.GetHashCode()?

推荐答案

好的,我最好把这个写下来.这本书非常不准确.Object.GetHashCode() 的值在 CLR 内部生成,并在第一次调用 GetHashCode() 时按需计算.我将引用 SSCLI20 发行版中的代码,clr/src/vm/thread.h 具有生成数字的函数,它看起来像这样(为了可读性进行了编辑):

Okay, I'd better write this up. The book is very inaccurate. The value for Object.GetHashCode() is generated inside the CLR and is calculated on demand, whenever GetHashCode() is called the first time. I'll quote the code from the SSCLI20 distribution, clr/src/vm/thread.h has the function that produces the number, it looks like this (edited for readability):

inline DWORD GetNewHashCode()
{
    // Every thread has its own generator for hash codes so that we won't get into a 
    // situation where two threads consistently give out the same hash codes.
    // Choice of multiplier guarantees period of 2**32
    // see Knuth Vol 2 p16 (3.2.1.2 Theorem A).
    DWORD multiplier = m_ThreadId*4 + 5;
    m_dwHashCodeSeed = m_dwHashCodeSeed*multiplier + 1;
    return m_dwHashCodeSeed;
}

之后它被存储在对象的所谓同步块中,以便后续调用返回相同的值.生成的 32 位中只有 26 位被实际存储,同步块需要一些状态位的空间.仍然足够好以生成非常高质量的哈希码,冲突非常罕见.

After which it is stored in the so-called sync block of the object so subsequent calls return the same value. Only 26 of the generated 32 bits are actually stored, the sync block needs space for some status bits. Still plenty good enough to generate a very high quality hash code, collisions are quite rare.

该代码中存在 m_ThreadId 变量可以使用解释.随机数生成器种子为每个单独的线程存储.避免必须锁定的技巧.

The presence of the m_ThreadId variable in that code can use an explanation. The random number generator seed is stored for each individual thread. A trick to avoid having to take a lock.

m_dwHashCodeSeed 在 Thread 构造函数中初始化如下:

The m_dwHashCodeSeed is initialized in the Thread constructor like this:

   // Initialize this variable to a very different start value for each thread
   // Using linear congruential generator from Knuth Vol. 2, p. 102, line 24
   dwHashCodeSeed = dwHashCodeSeed * 1566083941 + 1;
   m_dwHashCodeSeed = dwHashCodeSeed;

与:

   static  DWORD dwHashCodeSeed = 123456789;

这篇关于Object.GetHashCode() 的实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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