嵌套协方差是否变为逆变?

Is nested CoVariance becomes Contravariance?

我理解 CoVariance 和 CotraVariance 的概念,当需要将接口标记为 Read-only 时,我们使用 out T 并且对于 Write-only 接口,我们在 T 中使用 以便这些确保类型安全在对象的获取和设置方面。但是当我们嵌套这些时,ContraVariance 如何被视为 CoVariance。例如:

interface IObservable<out T>
{
    IDisposable Subscribe(IObserver<T> o);
}
interface IObserver<in T>
{
    void OnNext(T t);

    void OnError(Exception e);

    void OnCompleted();
}

请举例说明嵌套的事物如何改变它们的方差。 或者请将我重定向到一个好的阅读 Material。提前致谢。

让我们为引用类型的 "is a" 关系编写 (一种修改后的小于号)。例如 Elephant ⊂ IMammalIMammal ⊂ IAnimal.

先看IObserver<>

interface IObserver<in T>
{
    void OnNext(T t);
    // other members irrelevant
}

"in"表示它是逆变的。逆变的意思是:

If X ⊂ Y, then IObserver<Y> ⊂ IObserver<X>.

相反是因为XY的顺序在你"apply IObserver<·> on both sides of the "时改变了。这类似于将不等式(来自数学)乘以两边的 negative 数。您必须交换不等式的两侧(或将 变成 )。

之所以允许在T中有IObserver<T>逆变是因为T只用于方法中的一个值参数(即OnNext) .

假设我们有一个 IObserver<IMammal> 的实例。这可以在其 OnNext(IMammal t) 方法中接受任何 IMammal。这个实例也可以充当 IObserver<Elephant> 吗?是的,因为如果它可以接受任何 IMmammal,那么特别是它可以接受 Elephant,因此逆变是安全可靠的。因为Elephant"is an"IMammal,所以IObserver<IMammal>"is an"IObserver<Elephant>.

逆变使关系反转。

现在,让我们看看另一种类型(现在我们来看看你要问的是什么!)。我将它从 IObservable<> 重命名为 IVable<>:

interface IVable<out T>
{
    IDisposable Subscribe(IObserver<T> o);
}

"out"表示协变。协变意味着:

If X ⊂ Y, then IVable<X> ⊂ IVable<Y>.

这就像在数学中,将不等式的两边都乘以一个 正数 数。 XY 交换(co-)。

但是,当 IVable<T> 有一个接受 "something with T" 的方法 Subscribe 时,它怎么可能是协变的呢?那是因为 "something" 在 T!

中是逆变的

让我们看看它是否安然无恙。所以,假设我们有一个 IVable<IMammal> 的实例。这意味着它有一个 Subscribe 可以接受任何 IObserver<IMammal>。但是后者是逆变的,所以因为一个IMammal"is an"IAnimal,那么任何IObserver<IAnimal>"is an"IObserver<IMammal>。因此,这向我们表明,我们的 IVable<IMammal> 可以充当协方差指示的 IVable<IAnimal>。所以一切都很好。

结论:采用 "in" 在 T 逆变 的东西,其行为类似于 T 中的 "out"。类似地,发送 "out" 在 Tcontravariant 的东西,就像在 T.

中的 "in"