Search code examples
c#.netgethashcode

GetHashCode Equality


I've wondered about this, so I figure I'll ask it.

Most places you'll see use the same semantic logic for overriding Equals as GetHashCode for memberwise equality...however they usually use different implementations:

    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }
        var other = (MyType)obj;
        if (other.Prop1 != Prop1)
        {
            return false;
        }
        return true;
    }

    public override int GetHashCode()
    {
        int hash = -657803396;
        num ^= Prop1.GetHashCode();
        return num;
    }

If you're implementing memberwise equality for your type (lets say for storing in a dictionary), why not just override GetHashCode then do something like this for Equals:

    public override bool Equals(object obj)
    {
        return this.HashEqualsAndIsSameType(obj);
    }

    public static bool HashEquals(this object source, object obj)
    {
        if (source != null && obj != null)
        {
            return source.GetHashCode() == obj.GetHashCode();
        }
        if (source != null || obj != null)
        {
            return false;
        }
        return true;
    }

    public static bool HashEqualsAndIsSameType<T>(this T source, object obj)
    {
        return (obj == null || obj.GetType() == typeof(T)) && source.HashEquals(obj);
    }

Solution

  • Because there is a real risk of conflicts. Hash-codes are not unique. They can (when different) prove inequality, but never equality. When looking for an item:

    • get the hash-code(s)
    • if the hash-code is different, the object is different; discard it
    • if the hash-code is the same, check Equals:
    • if Equals reports true they are the same
    • else discard

    Consider long... since hash-code is int, it is easy to see that there are lots and lots of conflicts.