IEnumerable<T>
是 co-variant 但它不支持值类型,只支持引用类型。下面的简单代码编译成功:
IEnumerable<string> strList = new List<string>();
IEnumerable<object> objList = strList;
但从 string
改变至 int
会得到编译错误:
IEnumerable<int> intList = new List<int>();
IEnumerable<object> objList = intList;
原因在MSDN中解释:
Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.
我搜索了一下,发现有些问题提到原因是值类型和引用类型之间的装箱。但我仍然不太清楚为什么拳击是原因?
谁能简单而详细地解释为什么协变和逆变不支持值类型以及装箱对此有何影响?
最佳答案
基本上,当 CLR 可以确保不需要对值进行任何表示性更改时,方差适用。引用文献看起来都一样 - 所以你可以使用 IEnumerable<string>
作为IEnumerable<object>
表示没有任何变化; native 代码本身根本不需要知道您正在使用这些值做什么,只要基础架构保证它肯定有效即可。
对于值类型,这不起作用 - 处理 IEnumerable<int>
作为IEnumerable<object>
,使用序列的代码必须知道是否执行装箱转换。
您可能想阅读 Eric Lippert 的 blog post on representation and identity有关此主题的更多信息。
编辑:我自己重读了埃里克的博文,它至少与代表一样重要,尽管这两者是相关的。特别是:
This is why covariant and contravariant conversions of interface and delegate types require that all varying type arguments be of reference types. To ensure that a variant reference conversion is always identity-preserving, all of the conversions involving type arguments must also be identity-preserving. The easiest way to ensure that all the non-trivial conversions on type arguments are identity-preserving is to restrict them to be reference conversions.
关于c# - 为什么协变和逆变不支持值类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12454794/