Почему IEquatable T не делал контравариантным в T для С# 4.0?
IEquatable < Т > может быть объявлено контравариантным в T, поскольку он использует только T во входной позиции (или, что эквивалентно, U, являющийся подтипом T, должен подразумевать, что IEquatable <T> является [подтипом] IEquatable <U> ).
Итак, почему команда BCL не аннотировала его (для С# 4.0) с ключевым словом "in", как это было со многими другими универсальными интерфейсами (например, полностью аналогичными IComparable)?
Ответы
Ответ 1
Я думаю, что это в основном по философской причине, а не по техническому ограничению, поскольку вполне возможно просто аннотировать интерфейс. IEquatable<T>
предназначен для сравнения объектов одного и того же типа для точного равенства. Экземпляр суперкласса обычно не считается равным экземпляру подкласса. Равенство в этом смысле также подразумевает равенство типов. Это немного отличается от IComparable<in T>
. Может быть разумным определять относительный порядок сортировки для разных типов.
Чтобы процитировать страницу MSDN на IEquatable<T>
:
Примечания для исполнителей:
Замените параметр типа интерфейса IEquatable<T>
на тип, реализующий этот интерфейс.
Это предложение далее демонстрирует тот факт, что IEquatable<T>
предназначен для работы между экземплярами одного конкретного типа.
Ответ 2
Наследуемые типы обычно не реализуют IEquatable<T>
. Если IEquatable<T>
включил метод GetHashCode()
, можно было бы определить семантику IEquatable<T>
, чтобы сказать, что элементы должны сравниваться равными при проверке как T. К сожалению, тот факт, что IEquatable<T>
связан с одним и тем же хэш-кодом как Object.Equals
, означает, что вообще IEquatable<T>
должен реализовать по существу ту же семантику, что и Object.Equals
.
Следовательно, если реализация IEquatable<BaseClass>
делает в нем что-либо, кроме вызова Object.Equals
, производный класс, который переопределяет Object.Equals
и GetHashCode()
и не выполняет повторное выполнение IEquatable<BaseClass>
, будет в конечном итоге сломанным реализация этого интерфейса; реализация IEquatable<BaseClass>
, которая просто вызывает Object.Equals
, будет работать отлично, даже в этом сценарии, но не даст реального преимущества над классом, который не реализует IEquatable<T>
.
Учитывая, что наследуемые классы не должны внедрять IEquatable<T>
, в первую очередь, понятие ковариации не относится к надлежащим реализациям интерфейса.