【问题标题】:Is covariance all about accepting values?协方差是关于接受值的吗?
【发布时间】:2019-12-30 15:29:08
【问题描述】:

协方差就是接受值吗?

我正在通过 CLR via C# 一书学习 C#。我看到以下摘录:

由于 T 是协变的,因此可以成功编译并运行以下代码:

// This method accepts an IEnumerable of any reference type
Int32 Count(IEnumerable<Object> collection) { ... }

...
// The call below passes an IEnumerable<String> to Count
Int32 c = Count(new[] { "Grant" }); 

我在这里很困惑。因为协方差是关于具有作为所需类型的基本类型之一的类型。因此,协方差仅在返回类型的上下文中使用。而在上面的示例中,我们有一个 String(派生自 Object,因此它是逆变的,但不是协变的),它用于传递参数(但不返回值)的上下文中。

那么,我们应该在上面的例子中使用逆变而不是协变(意思是书中有错误)?

更新

在 cmets 之后,我得到了另一个问题。以下定义正确吗?

逆变意味着泛型类型参数可以从一个类变为一个类 从中衍生出来的。在 C# 中,您使用 in 关键字指示逆变泛型类型参数。 逆变泛型类型参数只能出现在输入位置,例如方法的 论据。

协变意味着泛型类型参数可以从一个类更改为其基类之一 类。在 C# 中,您使用 out 关键字指示协变泛型类型参数。协变

【问题讨论】:

  • Covariancecontravariance 启用数组类型、委托类型和泛型类型参数的隐式引用转换。 Covariance 保留了赋值兼容性,而逆变换了它...see more here,这不是书中的错误,而且是正确的。
  • IEnumerable&lt;T&gt;T 上是协变的,这本书是准确的。

标签: c# generics covariance contravariance


【解决方案1】:

正如乔希指出的那样,这本书是正确的。

如果您想从其他来源确认,可以查看this link

IEnumerable&lt;Cat&gt;IEnumerable&lt;Animal&gt; 的子类型。保留子类型是因为 IEnumerable&lt;T&gt;T 是协变的。

C# 中用于这些概念的两个关键字是 out 表示协变,in 表示逆变。在IEnumerable&lt;T&gt; 的情况下,这将转换为IEnumerable&lt;out T&gt;

希望这会有所帮助。

更新

您必须按如下方式反转您的定义。

协变 表示泛型类型参数可以是某个类以及它的所有派生类(IEnumerable&lt;Object&gt; 可以是IEnumerable&lt;String&gt;,因为StringObject 的子类型)。在 C# 中,您使用 out 关键字指示协变泛型类型参数。

逆变意味着泛型类型参数可以从 类到它的基类之一。在 C# 中,您表示逆变 带有 in 关键字的泛型类型参数。

【讨论】:

  • 另外in 仅适用于参数,out 适用于返回类型,这些只能应用于泛型接口。
  • 我对这个答案的问题是短语可以从一个类更改为从它派生的类改变是什么意思?您不能将IEnumerable&lt;Object&gt; 分配给IEnumerable&lt;String&gt;,但看起来这就是您所说的。我猜你的意思是IEnumerable&lt;Object&gt; 实际上可以是IEnumerable&lt;String&gt;。作为一个长期对协变和逆变感到困惑的人,我认为在这里使用 change 会让人感到困惑,你不觉得吗?
  • @Joelius 感谢您指出这一点,我认识到我也遇到过同样的情况,事情很快就会变得混乱。我的答案现在更容易理解了吗? :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 2013-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多