Ниже приводятся жалобы:
interface IInvariant<TInv> {}
interface ICovariant<out TCov> {
IInvariant<TCov> M(); // The covariant type parameter `TCov'
// must be invariantly valid on
// `ICovariant<TCov>.M()'
}
interface IContravariant<in TCon> {
void M(IInvariant<TCon> v); // The contravariant type parameter
// `TCon' must be invariantly valid
// on `IContravariant<TCon>.M()'
}
но я не могу представить, где это не было бы безопасным для типа. (snip *) Является ли это причиной того, что это запрещено, или есть ли другой случай, который нарушает безопасность типа, о которой я не знаю?
* Мои первоначальные мысли были, по общему признанию, запутаны, но, несмотря на это, ответы очень тщательны, и @Theodoros Chatzigiannakis даже с большой точностью проанализировал мои первоначальные предположения.
Наряду с хорошим ударом от ретроспективы я понимаю, что ложно предположил, что сигнатура типа ICovariant::M
остается Func<IInvariant<Derived>>
, когда ее ICovariant<Derived>
присваивается a ICovariant<Base>
. Тогда, приписывая, что M
- Func<IInvariant<Base>>
будет выглядеть отлично от ICovariant<Base>
, но, конечно, будет незаконным. Почему бы просто не запретить этот последний, явно незаконный литье? (так я думал)
Я чувствую, что эта ложная и тангенциальная гипотеза умаляет вопрос, поскольку Эрик Липперт также указывает, но в исторических целях отрывочная часть:
Наиболее интуитивным объяснением для меня является то, что, беря
ICovariant
в качестве примера, из ковариантаTCov
следует, что методIInvariant<TCov> M()
можно отличить от некоторогоIInvariant<TSuper> M()
, гдеTSuper super TCov
, что нарушает инвариантностьTInv
вIInvariant
. Однако эта импликация не представляется необходимой: инвариантностьIInvariant
наTInv
может быть легко реализована путем отказа от приведенияM
.