我将协方差和CotraVariance的概念理解为,当接口需要标记为只读时,我们使用T,对于只写接口,我们在T中使用,以便确保类型安全而不是获取和设置对象的东西。但是当我们嵌套这些时,逆方差如何被视为协方差。例如:
interface IObservable<out T>
{
IDisposable Subscribe(IObserver<T> o);
}
interface IObserver<in T>
{
void OnNext(T t);
void OnError(Exception e);
void OnCompleted();
}
请用一个例子来解释嵌套的东西是如何改变它们的方差的。 或者请把我重定向到一个好的阅读材料。提前谢谢。
让我们为引用类型的"is a"关系编写⊂
(一种修改后的小于符号)。例如Elephant ⊂ IMammal
或IMammal ⊂ IAnimal
。
先看IObserver<>
:
interface IObserver<in T>
{
void OnNext(T t);
// other members irrelevant
}
"in"意味着它是逆变的。逆变意味着:
如果
X ⊂ Y
,则IObserver<Y> ⊂ IObserver<X>
。
相反,是因为当您"在⊂
的两侧应用IObserver<·>
"时,X
和Y
的顺序会发生变化。这类似于将不等式(来自数学)乘以两边的负数。你必须交换不平等的两面(或将⊂
变成⊃
)。
之所以允许在T
中具有IObserver<T>
逆变T
是因为 仅用于方法(即OnNext
)中的值参数。
假设我们有一个IObserver<IMammal>
的实例。这可以在其OnNext(IMammal t)
方法中采用任何IMammal
。此实例也可以充当IObserver<Elephant>
?是的,因为如果它可以接受任何IMmammal
,那么特别是它可以接受Elephant
,所以逆变是安然无恙的。因为Elephant
"是一个"IMammal
,那么IObserver<IMammal>
"是一个"IObserver<Elephant>
。
逆变颠倒了关系。
现在,让我们看看另一种类型(现在我们来问你问什么!我将其从IObservable<>
重命名为IVable<>
:
interface IVable<out T>
{
IDisposable Subscribe(IObserver<T> o);
}
"出"表示协变。协变意味着:
如果
X ⊂ Y
,则IVable<X> ⊂ IVable<Y>
。
这就像在数学中,当你把不等式的两边都乘以一个正数时。X
和Y
不交换 (co-)。
但是,当IVable<T>
有一个方法时,它怎么可能是协变的,Subscribe
,它接受"有T
的东西"?那是因为那个"东西"在T
是逆变的!
让我们看看它是否安然无恙。因此,假设我们有一个实例,该实例是IVable<IMammal>
.这意味着它有一个可以接受任何IObserver<IMammal>
的Subscribe
.但后者是逆变的,所以因为IMammal
"是"IAnimal
,所以任何IObserver<IAnimal>
"是"IObserver<IMammal>
。因此,这表明我们的IVable<IMammal>
可以充当协方差所指示的IVable<IAnimal>
。所以一切都很好。
结论:在T
中"输入"的东西,就像在T
中"退出"一样。同样,发送"出"的东西在T
中是逆变的,就像T
中的"进"。