I’ve been thinking about this question for a bit and after a bit of consideration I agree that implementing IEquatable<T>
and IComparable<T>
should only be done on sealed types.
I went back and forth for a bit but then I thought of the following test. Under what circumstances should the following ever return false? IMHO, 2 objects are either equal or they are not.
public void EqualitySanityCheck<T>(T left, T right) where T : IEquatable<T> {
var equals1 = left.Equals(right);
var equals2 = ((IEqutable<T>)left).Equals(right);
Assert.AreEqual(equals1,equals2);
}
The result of IEquatable<T>
on a given object should have the same behavior as Object.Equals
assuming the comparer is of the equivalent type. Implementing IEquatable<T>
twice in an object hierarchy allows for, and implies, there are 2 different ways of expressing equality in your system. It’s easy to contrive any number of scenarios where IEquatable<T>
and Object.Equals
would differ since there are multiple IEquatable<T>
implementations but only a single Object.Equals
. Hence the above would fail and create a bit of confusion in your code.
Some people may argue that implementing IEquatable<T>
at a higher point in the object hierarchy is valid because you want to compare a subset of the objects properties. In that case you should favor an IEqualityComparer<T>
which is specifically designed to compare those properties.