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

I saw this code recently in a struct and I was wondering what base.GetHashCode actually does.

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

The coreclr repo has 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.

However, the code isn't there, and it looks like that's not quite what happens. Sample:

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

Output on my box:

42119818
372029398
372029397

Changing the value of y doesn't appear to change the hash code of foo.

However, if we make the fields int values instead, then more than the first field affects the output.

In short: this is complex, and you probably shouldn't depend on it remaining the same across multiple versions of the runtime. Unless you're really, really confident that you don't need to use your custom struct as a key in a hash-based dictionary/set, I'd strongly recommend overriding GetHashCode and Equals (and implementing IEquatable<T> to avoid boxing).

people

See more on this question at Stackoverflow