Equality Members

Thursday, June 16, 2011 11:48 AM

I was watching a presentation today and noticed an implementation of GetHashCode() that was... less than perfect :)

For those without the luxury of Resharper, I thought I'd create a few examples of implementing the equality members. For a refresher on defining equality, see this MSDN article. Note that, while technically optional, it is recommended to overload the == and != operators too.

public class IntPrimaryKey : IEquatable<IntPrimaryKey>
{
    public int PrimaryKey { get; set; }

    public bool Equals(IntPrimaryKey other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return PrimaryKey == other.PrimaryKey;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as IntPrimaryKey);
    }

    public override int GetHashCode()
    {
        return PrimaryKey;
    }
}

public class StringPrimaryKey : IEquatable<StringPrimaryKey>
{
    public string PrimaryKey { get; set; }

    public bool Equals(StringPrimaryKey other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Equals(PrimaryKey, other.PrimaryKey);
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as StringPrimaryKey);
    }

    public override int GetHashCode()
    {
        return PrimaryKey == null ? 0 : PrimaryKey.GetHashCode();
    }
}

public class MultiNumberPrimaryKey : IEquatable<MultiNumberPrimaryKey>
{
    public int PrimaryKey1 { get; set; }
    public int PrimaryKey2 { get; set; }

    public bool Equals(MultiNumberPrimaryKey other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return PrimaryKey1 == other.PrimaryKey1 && PrimaryKey2 == other.PrimaryKey2;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as MultiNumberPrimaryKey);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (PrimaryKey1 * 397) ^ PrimaryKey2;
        }
    }
}

public class MultiStringPrimaryKey : IEquatable<MultiStringPrimaryKey>
{
    public string PrimaryKey1 { get; set; }
    public string PrimaryKey2 { get; set; }

    public bool Equals(MultiStringPrimaryKey other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Equals(PrimaryKey1, other.PrimaryKey1) && Equals(PrimaryKey2, other.PrimaryKey2);
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as MultiStringPrimaryKey);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return ((PrimaryKey1 == null ? 0 : PrimaryKey1.GetHashCode()) * 397) ^ (PrimaryKey2 == null ? 0 : PrimaryKey2.GetHashCode());
        }
    }
}

public class MultiMixedPrimaryKey : IEquatable<MultiMixedPrimaryKey>
{
    public int PrimaryKey1 { get; set; }
    public string PrimaryKey2 { get; set; }

    public bool Equals(MultiMixedPrimaryKey other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return PrimaryKey1 == other.PrimaryKey1 && Equals(PrimaryKey2, other.PrimaryKey2);
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as MultiMixedPrimaryKey);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (PrimaryKey1 * 397) ^ (PrimaryKey2 == null ? 0 : PrimaryKey2.GetHashCode());
        }
    }
}

public class MultiPrimaryKey : IEquatable<MultiPrimaryKey>
{
    public int PrimaryKey1 { get; set; }
    public int PrimaryKey2 { get; set; }
    public int PrimaryKey3 { get; set; }
    public int PrimaryKey4 { get; set; }

    public bool Equals(MultiPrimaryKey other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return PrimaryKey1 == other.PrimaryKey1 && PrimaryKey2 == other.PrimaryKey2 && PrimaryKey3 == other.PrimaryKey3 && PrimaryKey4 == other.PrimaryKey4;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as MultiPrimaryKey);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int result = PrimaryKey1;
            result = (result * 397) ^ PrimaryKey2;
            result = (result * 397) ^ PrimaryKey3;
            result = (result * 397) ^ PrimaryKey4;
            return result;
        }
    }
}

public class MultiPrimaryKey2 : IEquatable<MultiPrimaryKey2>
{
    public string PrimaryKey1 { get; set; }
    public string PrimaryKey2 { get; set; }
    public string PrimaryKey3 { get; set; }
    public string PrimaryKey4 { get; set; }

    public bool Equals(MultiPrimaryKey2 other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Equals(PrimaryKey1, other.PrimaryKey1) && Equals(PrimaryKey2, other.PrimaryKey2) && Equals(PrimaryKey3, other.PrimaryKey3) && Equals(PrimaryKey4, other.PrimaryKey4);
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as MultiPrimaryKey2);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int result = PrimaryKey1 == null ? 0 : PrimaryKey1.GetHashCode();
            result = (result * 397) ^ (PrimaryKey2 == null ? 0 : PrimaryKey2.GetHashCode());
            result = (result * 397) ^ (PrimaryKey3 == null ? 0 : PrimaryKey3.GetHashCode());
            result = (result * 397) ^ (PrimaryKey4 == null ? 0 : PrimaryKey4.GetHashCode());
            return result;
        }
    }
}
Tags: .net, bestpractices