base.GetHashCode() 是如何为结构实现的?

How is base.GetHashCode() implemented for a struct?

我最近在 struct 中看到这段代码,我想知道 base.GetHashCode 到底做了什么。

    public override int GetHashCode()
    {
        var hashCode = -592410294;
        hashCode = hashCode * -1521134295 + base.GetHashCode();
        hashCode = hashCode * -1521134295 + m_Value.GetHashCode();
        return hashCode;
    }

一个结构体的基础class是ValueTypeclass,源码在网上。他们很有帮助地留下了描述其工作原理的评论:

ValueType.GetHashCode:

/*=================================GetHashCode==================================
**Action: Our algorithm for returning the hashcode is a little bit complex.  We look
**        for the first non-static field and get it's hashcode.  If the type has no
**        non-static fields, we return the hashcode of the type.  We can't take the
**        hashcode of a static member because if that member is of the same type as
**        the original type, we'll end up in an infinite loop.
**Returns: The hashcode for the type.
**Arguments: None.
**Exceptions: None.
==============================================================================*/
[System.Security.SecuritySafeCritical]  // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern override int GetHashCode();

coreclr 仓库有 this comment:

Action: Our algorithm for returning the hashcode is a little bit complex. We look for the first non-static field and get it's hashcode. If the type has no non-static fields, we return the hashcode of the type. We can't take the hashcode of a static member because if that member is of the same type as the original type, we'll end up in an infinite loop.

但是,代码不存在,看起来 完全 不是这样。示例:

using System;

struct Foo
{
    public string x;
    public string y;
}

class Test
{
    static void Main()
    {
        Foo foo = new Foo();
        foo.x = "x";
        foo.y = "y";
        Console.WriteLine(foo.GetHashCode());
        Console.WriteLine("x".GetHashCode());
        Console.WriteLine("y".GetHashCode());
    }
}

我盒子上的输出:

42119818
372029398
372029397

更改 y 的值似乎不会更改 foo 的哈希码。

但是,如果我们将字段设为 int 值,那么第一个字段会影响输出。

简而言之:这很复杂,您可能不应该依赖它在运行时的多个版本中保持不变。除非您真的非常有信心不需要将自定义结构用作基于散列的 dictionary/set 中的键,否则我强烈建议覆盖 GetHashCodeEquals (并实施 IEquatable<T> 以避免装箱)。