Страницы

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

воскресенье, 15 декабря 2019 г.

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

#c_sharp #net #generics #компилятор


Зачем компилятор запрещает делать такие штуки как

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();
    }
}


Тут если убрать в классе явную реализацию, то компилятору захочется поругаться на
то, что нет ограничения в неявной реализации. Почему? Откуда растут ноги у таких запретов
компилятора? Зачем их ввели (желательно на примере, где видно, что без них было бы хуже)?
    


Ответы

Ответ 1



Проблема со второй частью очевидна. Если у вас нет явной реализации, то метод 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 подходит для контравариантных, но не ковариантных параметров, то есть, является контравариантным использованием.

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

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