Is there a complete IEquatable implementation reference?

.net, c#, equals, gethashcode, iequatable

Solution

Implementing `IEquatable<T>` for a Value Type

Implementing `IEquatable<T>` for a value type is a little bit different than for a reference type. Let's assume we have the Implement-Your-Own-Value-Type archetype, a Complex number struct.

public struct Complex
{
    public double RealPart { get; set; }
    public double ImaginaryPart { get; set; }
}

Our first step would be to implement `IEquatable<T>` and override `Object.Equals` and `Object.GetHashCode`:

public bool Equals(Complex other)
{
    // Complex is a value type, thus we don't have to check for null
    // if (other == null) return false;

    return (this.RealPart == other.RealPart)
        && (this.ImaginaryPart == other.ImaginaryPart);
}

public override bool Equals(object other)
{
    // other could be a reference type, the is operator will return false if null
    if (other is Complex)
        return this.Equals((Complex)other);
    else
        return false;
}

public override int GetHashCode()
{
    return this.RealPart.GetHashCode() ^ this.ImaginaryPart.GetHashCode();
}

With very little effort we have a correct implementation, excepting the operators. Adding the operators is also a trivial process:

public static bool operator ==(Complex term1, Complex term2)
{
    return term1.Equals(term2);
}

public static bool operator !=(Complex term1, Complex term2)
{
    return !term1.Equals(term2);
}

An astute reader would notice that we should probably implement `IEquatable<double>` since `Complex` numbers could be interchangeable with the underlying value type.

public bool Equals(double otherReal)
{
    return (this.RealPart == otherReal) && (this.ImaginaryPart == 0.0);
}

public override bool Equals(object other)
{
    // other could be a reference type, thus we check for null
    if (other == null) return base.Equals(other);

    if (other is Complex)
    {
        return this.Equals((Complex)other);
    }
    else if (other is double)
    {
        return this.Equals((double)other);
    }
    else
    {
        return false;
    }
}

We need four operators if we add `IEquatable<double>`, because you can have `Complex == double` or `double == Complex` (and the same for `operator !=`):

public static bool operator ==(Complex term1, double term2)
{
    return term1.Equals(term2);
}

public static bool operator ==(double term1, Complex term2)
{
    return term2.Equals(term1);
}

public static bool operator !=(Complex term1, double term2)
{
    return !term1.Equals(term2);
}

public static bool operator !=(double term1, Complex term2)
{
    return !term2.Equals(term1);
}

So there you have it, with minimal effort we have a correct and useful implementation `IEquatable<T>` for a value type:

public struct Complex : IEquatable<Complex>, IEquatable<double>
{
}

Problem

Many of my questions here on SO concerns IEquatable implementation. I found it being extremely difficult to implement correctly, because there are many hidden bugs in the naïve implementation, and the articles I found about it are quite incomplete. I want to find or write a definitive reference which must include: - How to implement IEquatable correctly - How to override Equals correctly - How to override GetHashCode correctly - How to implement the ToString method correctly - How to implement the operator == correctly - How to implement the operator != correctly Such a complete reference already exists? PS: Even MSDN reference seems flawed to me

Original source