协方差和反方差不支持值类型的原因

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (13)

IEnumerable<T>协变但它不支持值类型,只支持引用类型。成功编译了以下简单代码:

IEnumerable<string> strList = new List<string>();
IEnumerable<object> objList = strList;

但从stringint将得到编译错误:

IEnumerable<int> intList = new List<int>();
IEnumerable<object> objList = intList;

方差仅适用于引用类型;如果为变量类型参数指定值类型,则该类型参数对于结果构造的类型是不变的。

请有人给出一个简单而详细的解释为什么协方差和反方差不支持值类型,以及如何拳击影响这个?

提问于
用户回答回答于

基本上,当CLR能够确保它不需要做任何代表性变化为价值干杯。引用看起来都一样-所以您可以使用IEnumerable<string>作为IEnumerable<object>表示没有任何改变。

对于值类型,这是不起作用的--将IEnumerable<int>作为IEnumerable<object>,使用序列的代码必须知道是否执行装箱转换。

特别是:

这就是为什么接口类型和委托类型的协变和反变转换要求所有不同类型的参数都是引用类型的原因。为了确保变量引用转换始终保持标识,所有涉及类型参数的转换都必须保持标识。确保类型参数上的所有非平凡转换都保持身份的最简单方法是将它们限制为引用转换。

用户回答回答于

下面是字符串的集合:

IEnumerable<string> strings = new[] { "A", "B", "C" };

你可以想到strings如下所示:

[0] : string reference -> "A"
[1] : string reference -> "B"
[2] : string reference -> "C"

它是三个元素的集合,每个元素都是对一个字符串的引用。您可以将此转换为对象的集合:

IEnumerable<object> objects = (IEnumerable<object>) strings;

基本上,它是相同的表示形式,但现在引用是对象引用:

[0] : object reference -> "A"
[1] : object reference -> "B"
[2] : object reference -> "C"

表示法是一样的。引用只是被不同的对待;不能再访问string.Length属性,但仍然可以调用object.GetHashCode()。将其与INT集合进行比较:

IEnumerable<int> ints = new[] { 1, 2, 3 };
[0] : int = 1
[1] : int = 2
[2] : int = 3

若要将此转换为IEnumerable<object>数据必须通过装箱INT来转换:

[0] : object reference -> 1
[1] : object reference -> 2
[2] : object reference -> 3

这种转换需要的不仅仅是一个转换。

扫码关注云+社区