Контравариантный универсальный параметр не может быть выведен, поскольку он не может быть гарантированно безопасным во время компиляции, и разработчики C # приняли решение не продлевать необходимые проверки во время выполнения.
Этокороткий ответ, а вот немного более длинный ...
Что такое дисперсия?
Дисперсия - это свойство преобразования , примененное к иерархии типов:
- Если результатом преобразования является иерархия типов, которая сохраняет «направление» исходной иерархии типов, преобразование является co -вариантным.
- Если результатом преобразования является иерархия типов, которая меняет исходное "направление", преобразование имеет contra -вариант.
- Если результатпреобразования представляет собой группу несвязанных типов, преобразование в -вариант.
Что такое дисперсия в C #?
В C # преобразование "«это» используется в качестве agэнергетический параметр ".Например, скажем, класс Parent
наследуется классом Child
.Давайте обозначим этот факт как: Parent
> Child
(потому что все Child
экземпляры также являются Parent
экземплярами, но не обязательно наоборот, следовательно, Parent
"больше").Скажем также, у нас есть общий интерфейс I<T>
:
- Если
I<Parent>
> I<Child>
, T является ковариантным (исходное «направление» между Parent
и Child
сохраняется). - Если
I<Parent>
<<code>I<Child>, T является контравариантным (исходное «направление» перевернуто). - Если
I<Parent>
не связано с I<Child>
, Tявляется инвариантом.
Итак, что потенциально небезопасно?
Если компилятор C # фактически согласился скомпилировать следующий код ...
class Parent {
}
class Child : Parent {
}
interface I<in T> {
T Get(); // Imagine this actually compiles.
}
class G<T> : I<T> where T : new() {
public T Get() {
return new T();
}
}
// ...
I<Child> g = new G<Parent>(); // OK since T is declared as contravariant, thus "reversing" the type hierarchy, as explained above.
Child child = g.Get(); // Yuck!
...это может привести к проблеме во время выполнения: создается экземпляр Parent
и присваивается ссылка на Child
.Поскольку Parent
не Child
, это неправильно!
Последняя строка выглядит нормально во время компиляции, поскольку объявлено, что I<Child>.Get
возвращает Child
, но мы не можем полностью «доверять» ейво время выполнения.Разработчики C # решили поступить правильно и полностью уловить проблему во время компиляции, избегая необходимости проверок во время выполнения (в отличие от массивов).
(для аналогичных, но «обратных»)причины, ковариантный универсальный параметр не может быть использован в качестве входных данных.)