Overriding GetHashCode for value types

I’ve written before that value types should override Object.Equals for performance reasons. GetHashCode should be overridden at the same time (for symmetry), but I’ve just learnt another good reason to override GetHashCode: the default implementation has a bug when your struct contains a nested value type for which value equality is not the same as bitwise equality.

As per Hans Passant’s detailed comment, the default ValueType.GetHashCode implementation (on the Microsoft CLR) XORs the bits of the struct together if it contains no reference types and has no padding.

Unfortunately, if the struct contains a member that can have two different bit patterns that represent the same logical value, this will generate different hash codes for values that should be considered equal. (The default Equals implementation will call the Equals methods of the nested types, so it is not subject to this bug.) The most common example is decimal: 1m and 1.0m have different bit representations in memory, so the following program produces rather unexpected output:

static void Main()
{
    Test t1 = new Test { Value = 1m };
    Test t2 = new Test { Value = 1.0m };
    Console.WriteLine(t1.Equals(t2)); // true

    Console.WriteLine(t1.GetHashCode() == t2.GetHashCode()); // false

}

struct Test
{
    public decimal Value;
}

If you’re implementing a value type that will ever be used as a key in a hashtable, always override Object.GetHashCode.

Posted by Bradley Grainger on October 04, 2010