Хотя IEquatable , как правило, не должен быть реализован незакрытыми классами, так как такой вывод будет играть странно с наследованием, если реализация просто не вызывает Object.Equals (в этом случае это будет бессмысленно), противоположная ситуация возникает с универсальным IComparable . Семантика для Object.Equals и IEquatable подразумевает, что всякий раз, когда IEquatable определен, его поведение должно отражать поведение Object.Equals (за исключением, возможно, более быстрого и избегания бокса). Два объекта типа DerivedFoo, которые сравниваются как равные, если рассматривать их как тип DerivedFoo, также должны сравниваться равными, если рассматривать их как объекты типа Foo, и наоборот. С другой стороны, вполне возможно, что два объекта типа DerivedFoo, которые имеют неравный ранг, если рассматривать их как тип DerivedFoo, должны иметь одинаковый ранг, если рассматривать их как тип Foo. Единственный способ убедиться в этом - использовать IComparable .
Предположим, например, что есть класс SchedulerEvent, который содержит поля ScheduledTime (типа DateTime) и ScheduledAction (типа MethodInvoker). Класс включает в себя подтипы SchedulerEventWithMessage (который добавляет поле Message типа string) и SchedulerEventWithGong (который добавляет поле GongVolume типа Double). Класс SchedulerEvent имеет естественное упорядочение по ScheduledTime, но вполне возможно, что события, которые неупорядочены относительно друг друга, будут неравными. Классы SchedulerEventWithMessage и SchedulerEventWithGong также имеют естественные упорядочения между собой, но не по сравнению с элементами класса SchedulerEvent.
Предположим, что у одного есть два события SchedulerEventWithMessage X и Y, запланированные на одно и то же время, но X.Message - "aardvark", а Y.Message - "zymurgy". ((IComparable ) X) .CompareTo (Y) должен сообщать ноль (поскольку события имеют равное время), но ((IComparable ) X) .CompareTo (Y) должен возвращать отрицательное число (так как «aardvark» роды перед "зимургой"). Если бы класс не вел себя таким образом, было бы трудно или невозможно последовательно упорядочить список, который содержит смесь объектов SchedulerEventWithMessage и SchedulerEventWithGong.
Кстати, можно утверждать, что было бы полезно, чтобы семантика IEquatable сравнивала объекты только на основе членов типа T, так что, например, IEquatable будет проверять ScheduledTime и ScheduledAction на равенство, но даже при применении к SchedulerEventWithMessage или SchedulerEventWithGong не будет проверять свойства Message или GongVolume. Действительно, это было бы полезно для семантики IEquatable , и я предпочел бы такую семантику, но для одной проблемы: Comparer .Default.GetHashCode (T) всегда вызывает одну и ту же функцию Object.GetHashCode () независимо от тип T. Это значительно ограничивает способность IEquatable изменять свое поведение в зависимости от типа T.