Почему универсальные интерфейсы не являются со-контрвариантными по умолчанию? - PullRequest
16 голосов
/ 30 августа 2010

Например, IEnumerable<T> interface:

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

В этом интерфейсе универсальный тип используется только в качестве возвращаемого типа метода интерфейса и не используется в качестве типа аргументов метода, поэтому он может быть ковариантным.Учитывая это, компилятор не может теоретически вывести отклонение от интерфейса?Если это возможно, почему C # требует, чтобы мы явно устанавливали ключевые слова co / contravariance.

Обновление : Как упоминал Джон Скит, этот вопрос можно разбить на подвопросы:

  1. Может определить компилятор genericТип co / Контравариантность по тому, как он используется внутри текущего универсального типа и всех его базовых типов?

    Например. Сколько общих параметров интерфейса из .NET Framework 4.0 могут быть автоматически помечены как ко / контравариантные без какой-либо двусмысленности?Около 70%, 80%, 90% или 100%?

  2. Если это возможно, должно применить ко / контравариантность к универсальным типам по умолчанию?По крайней мере для тех типов, которые он способен анализировать и выводить со / контравариантность из использования типа.

Ответы [ 2 ]

16 голосов
/ 30 августа 2010

Ну, здесь два вопроса.Во-первых, может ли компилятор всегда делать это?Во-вторых, должно это (если это возможно)?

По первому вопросу я перейду к Эрику Липперту, который сделал этот комментарий, когда я поднял именно эту проблему во 2-м издании.C # в глубине:

Мне не ясно, что мы разумно могли бы, даже если бы захотели.Мы можем легко придумать ситуации, которые требуют дорогостоящего глобального анализа всех интерфейсов в программе, чтобы обработать отклонения, и мы можем легко придумать ситуации, когда это либо <in T, out U>, либо <out T, in U>, и нет способа выбрать между ними,И с плохой производительностью, и с неоднозначными случаями это маловероятная особенность.

(Надеюсь, Эрик не возражает против того, чтобы я цитировал это дословно; ранее он был очень хорош в обмене такими идеями, поэтому я продолжупрошлая форма:)

С другой стороны, я подозреваю, что все еще есть случаи, когда можно сделать вывод без двусмысленности, поэтому второй пункт все еще актуален ...

Я не думаю, что это должно быть автоматическим, даже если компилятор может однозначно знать, что он действителен только одним способом.Хотя расширение интерфейса всегда в некоторой степени является серьезным изменением, обычно это не так, если вы единственный, кто его реализует.Однако, если люди полагаются на ваш интерфейс как вариант, вы, возможно, не сможете в состоянии добавлять методы к нему, не нарушая клиентов ... даже если они просто звонящие, а не разработчики.Методы, которые вы добавляете, могут изменить ранее ковариантный интерфейс, чтобы он стал инвариантным, и в этот момент вы нарушаете все вызывающие, которые пытаются использовать его ковариантно.

В принципе, я думаю, что это нормально, требовать, чтобы это было явным - этопроектное решение, которое вы должны принимать осознанно, а не просто случайно получить ковариацию / контравариантность, не задумываясь об этом.

5 голосов
/ 30 августа 2010

В этой статье объясняется, что существуют ситуации, которые компилятор не может вывести, и поэтому он предоставляет вам явный синтаксис:

interface IReadWriteBase<T>
{
    IReadWrite<T> ReadWrite();
}

interface IReadWrite<T> : IReadWriteBase<T>
{

}

Что вы выводите здесь in или out, оба работают?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...