Страницы

Поиск по вопросам

пятница, 26 октября 2018 г.

Ограничения компилятора в обобщениях

Зачем компилятор запрещает делать такие штуки как
interface II { void M() where V : T; }
Хотя, если убрать ограничение where V : T, то компилятор позволит это скомпилировать
И второй пример
interface II { void M() where V : T; }
class A : II { public void M()// where V : T { throw new NotImplementedException(); }
void II.M() { throw new NotImplementedException(); } }
Тут если убрать в классе явную реализацию, то компилятору захочется поругаться на то, что нет ограничения в неявной реализации. Почему? Откуда растут ноги у таких запретов компилятора? Зачем их ввели (желательно на примере, где видно, что без них было бы хуже)?


Ответ

Проблема со второй частью очевидна.
Если у вас нет явной реализации, то метод public void M() должен реализовать интерфейсный метод void M() where V : T. Соответственно отсутствие ограничения будет нарушением.
Для явной реализации интерфейса ограничения (неявно) применяются. т. к. вы не можете вызвать этот метод иначе, чем через интерфейс. Но для неявной реализации — то есть, обыкновенного метода, который можно вызывать напрямую — неявное применение ограничений было бы слишком непонятным для пользователей класса.

По поводу первой части, сообщение об ошибке даёт нужную информацию:
Invalid variance: The type parameter T must be contravariantly valid on II.M(). T is covariant.
Смотрите, out-параметр T является ковариантным. То есть, II является подтипом II
Пусть у нас есть класс
class C : II { void M() where V : Derived { } }
Тогда мы можем написать:
II ii = new C(); ii.M();
Но в объекте C у нас не может быть Base generic-параметром для M! То есть, как видите, where V : T подходит для контравариантных, но не ковариантных параметров, то есть, является контравариантным использованием

Комментариев нет:

Отправить комментарий