Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should be IEquatable<T>'s Equals() be implemented via IComparable<T>'s CompareTo()?

Tags:

c#

I've been looking for an answer on the internet but all I've found was:

Edit: Added some items in response to the answers

  • For IEquatable

    • I'm supposed to overload Equals(), GetHashCode(), == and != together.
    • I'm supposed to reduce redundancy via implementing != via ==.
    • I'm supposed to seal the class
  • For IComparable

    • I'm supposed to overload Equals(), GetHashCode(), <, >, <= and >= together.
    • In fact it is recommend to implement IEquatable when doing so
    • Overload the non-generic version of IComparable
    • CompareTo() == 0 should mean Equals() == true

So I've been thinking about this:

public bool Equals(T other)
{
    if ((object)other == null)
    {
        return false;
    }

    return CompareTo(other) == 0;
}

Am I overlooking something or is this ok?

like image 278
Johannes Avatar asked May 16 '15 13:05

Johannes


People also ask

When should you implement IEquatable?

In . NET you implement IEquatable if you want to modify equality of structs (not to forget implementing GetHashCode , == , != ) to go along with it.

What is IEquatable in C#?

The IEquatable<T> interface is used by generic collection objects such as Dictionary<TKey,TValue>, List<T>, and LinkedList<T> when testing for equality in such methods as Contains , IndexOf , LastIndexOf , and Remove . It should be implemented for any object that might be stored in a generic collection.


1 Answers

According to Eric Lippert, a former developer on the C# compiler team at Microsoft:

  • There are nine ways to do a comparison in C#: < <= > >= == != object.Equals(object) IEquatable<T>.Equals(T) IComparable<T>.CompareTo(T)
  • Ideally these should all be consistent with each other. That is, if x == y is true then x < y is false but x <= y and x.Equals(y) are true and x.CompareTo(y) is zero, and so on.

So, in his opinion, "ideally" x.CompareTo(y) == 0 implies x.Equals(y) == true and vice versa.

Eric then provides an example that implements everything using a private helper method:

public int CompareTo(Natural x) { return CompareTo(this, x); }
public static bool operator <(Natural x, Natural y) { return CompareTo(x, y) < 0; }
public static bool operator >(Natural x, Natural y) { return CompareTo(x, y) > 0; }
public static bool operator <=(Natural x, Natural y) { return CompareTo(x, y) <= 0; }
public static bool operator >=(Natural x, Natural y) { return CompareTo(x, y) >= 0; }
public static bool operator ==(Natural x, Natural y) { return CompareTo(x, y) == 0; }
public static bool operator !=(Natural x, Natural y) { return CompareTo(x, y) != 0; } 
public override bool Equals(object obj) { return CompareTo(this, obj as Natural) == 0; }
public bool Equals(Natural x) { return CompareTo(this, x) == 0; }

private static int CompareTo(Natural x, Natural y) { ... }
like image 58
Michael Liu Avatar answered Sep 19 '22 12:09

Michael Liu