简体   繁体   English

Object.GetHashCode()的实现

[英]Implementation of Object.GetHashCode()

I'm reading Effective C# and there is a comment about Object.GetHashCode() that I didn't understand: 我正在阅读Effective C#并且有一条关于Object.GetHashCode()的评论,我不明白:

Object.GetHashCode() uses an internal field in the System.Object class to generate the hash value. Object.GetHashCode()使用System.Object类中的内部字段来生成哈希值。 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. 这些键从1开始,每次创建任何类型的新对象时都会递增。 The object identity field is set in the System.Object constructor and cannot be modified later. 对象标识字段在System.Object构造函数中设置,以后不能修改。 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. 我试着查看Object.GetHashCode()的文档,但没有找到任何关于此的信息。

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());
            }
        }
    }
}

The first few numbers that were printed were: 打印的前几个数字是:

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

Which didn't seem to fit that 哪个似乎不合适

These keys start at 1 and increment every time a new object of any type gets created... Object.GetHashCode() returns this value 这些键从1开始,每次创建任何类型的新对象时都会递增... Object.GetHashCode()返回此值

Then, in order to find this "internal field in the System.Object " I tried using ReSharper decompiled sources but the code I found was 然后,为了在System.Object找到这个“内部字段”,我尝试使用ReSharper反编译源,但我找到的代码是

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

and again using decompiled sources I found that RuntimeHelpers.GetHashCode was implemented as 再次使用反编译源我发现RuntimeHelpers.GetHashCode实现为

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

following the MethodImpl attribute it seems that I can't view the implementation and this is a dead end for me. 在MethodImpl属性之后 ,似乎我无法查看实现,这对我来说是一个死胡同。

Can someone please explain the comment by the author (the first quote) ? 有人可以解释作者的评论(第一个引用)吗?

What is the internal field within the Object class and how it is used for the implementation of the Object.GetHashCode() ? Object类中的内部字段是什么以及如何使用它来实现Object.GetHashCode()

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. Object.GetHashCode()的值在CLR内部生成,并且只要第一次调用GetHashCode(),就会按需计算。 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): 我将引用SSCLI20发行版中的代码,clr / src / vm / thread.h具有生成数字的函数,它看起来像这样(为了便于阅读而编辑):

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;
}

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. 实际存储的32位中只有26位,同步块需要一些状态位空间。 Still plenty good enough to generate a very high quality hash code, collisions are quite rare. 仍然足以产生非常高质量的哈希码,碰撞是非常罕见的。

The presence of the m_ThreadId variable in that code can use an explanation. 该代码中m_ThreadId变量的存在可以使用解释。 The random number generator seed is stored for each individual thread. 为每个单独的线程存储随机数生成器种子。 A trick to avoid having to take a lock. 避免不得不锁定的诀窍。

The m_dwHashCodeSeed is initialized in the Thread constructor like this: m_dwHashCodeSeed在Thread构造函数中初始化,如下所示:

   // 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;

with: 有:

   static  DWORD dwHashCodeSeed = 123456789;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Object.GetHashCode - Object.GetHashCode 将Object.GetHashCode()转换为Guid - Converting Object.GetHashCode() to Guid Object.GetHashCode()对引用或值是唯一的吗? - Is Object.GetHashCode() unique to a reference or a value? 如何在重写GetHashCode()的类型上使用Object.GetHashCode() - How to use Object.GetHashCode() on a type that overrides GetHashCode() 关于如何正确覆盖object.GetHashCode()的一般建议和指南 - General advice and guidelines on how to properly override object.GetHashCode() 在没有不可变字段的类中重写Object.GetHashCode()时要返回什么? - What to return when overriding Object.GetHashCode() in classes with no immutable fields? 我的IEquatable仍在使用Object.GetHashcode for Dictionary <T> [] - My IEquatable is still using Object.GetHashcode for Dictionary<T>[] .NET SHA256与Object.GetHashCode() - .NET SHA256 Vs Object.GetHashCode() C#运算符重载:Object.Equals(object o)和Object.GetHashCode() - C# operator overloading: Object.Equals(object o) & Object.GetHashCode() 警告:“...覆盖Object.Equals(对象o)但不覆盖Object.GetHashCode()” - Warning: “… overrides Object.Equals(object o) but does not override Object.GetHashCode()”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM