嵌套协方差是否变为逆变?
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 ⊂ IMammal
或 IMammal ⊂ IAnimal
.
先看IObserver<>
:
interface IObserver<in T>
{
void OnNext(T t);
// other members irrelevant
}
"in"表示它是逆变的。逆变的意思是:
If X ⊂ Y
, then IObserver<Y> ⊂ IObserver<X>
.
相反是因为X
和Y
的顺序在你"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>
.
这就像在数学中,将不等式的两边都乘以一个 正数 数。 X
和 Y
未 交换(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" 在 T
中 contravariant 的东西,就像在 T
.
中的 "in"
我理解 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 ⊂ IMammal
或 IMammal ⊂ IAnimal
.
先看IObserver<>
:
interface IObserver<in T>
{
void OnNext(T t);
// other members irrelevant
}
"in"表示它是逆变的。逆变的意思是:
If
X ⊂ Y
, thenIObserver<Y> ⊂ IObserver<X>
.
相反是因为X
和Y
的顺序在你"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
, thenIVable<X> ⊂ IVable<Y>
.
这就像在数学中,将不等式的两边都乘以一个 正数 数。 X
和 Y
未 交换(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" 在 T
中 contravariant 的东西,就像在 T
.