[英]Implicit convertion of generic types parameterized with reference types vs value types
为什么C#隐式地将使用实现接口的引用类型参数化的泛型类型转换为使用实现的接口参数化的相同泛型类型,但不对引用类型执行相同的隐式转换?
从本质上讲,为什么第一行编译但第二行失败?
IEnumerable<IComparable<Version>> x = Enumerable.Empty<Version>();
IEnumerable<IComparable<int>> y = Enumerable.Empty<int>();
特别棒的是对描述此行为的规范部分的引用。
尽管名称是“隐式”,但隐式转换不适用,除非规则明确说明它们,并且规则在从IEnumerable<int>
转到IEnumerable<IComparable<int>>
时不允许装箱转换。 作为一个更简单的例子,出于同样的原因,你不能从IEnumerable<int>
转到IEnumerable<object>
,并且这个案例有很好的记录。
OK,首先,为什么会 IEnumerable<T>
转换到IEnumerable<IComparable<T>>
呢? 这将在§6.1.6( C#语言规范5.0 )中介绍:
隐式引用转换是:
[...]
- 从任何引用类型到接口或委托类型
T
如果它具有隐式标识或引用转换到接口或委托类型T 0
和T 0
是方差可转换(第13.1.3.2节)到T
并且§13.1.3.2说:
A型
T<A 1 , …, A n >
是方差-转换为一个类型T<B 1 , …, B n >
如果T
是一个接口或与变体类型参数中声明委托类型T<X 1 , …, X n >
,并且对于每个变体类型参数X i
,以下之一成立:
X i
是协变的,并且从A i
到B i
存在隐式参考或身份转换
由于IEnumerable<T>
在T
是协变的,这意味着如果存在从T
到IComparable<T>
的隐式引用或标识转换,则存在从IEnumerable<T>
到IEnumerable<IComparable<T>>
的隐式引用转换。 ,由于这些是方差可兑换的。
当然,我强调“参考”是有原因的。 由于Version
实现了IComparable<Version>
,因此存在隐式引用转换:
- 从任何类型
S
到任何接口类型T
,只要S
实现T
。
是的,现在,为什么IEnumerable<int>
隐式转换为IEnumerable<IComparable<int>>
? 毕竟, int
隐式转换为IComparable<int>
:
IComparable<int> x = 0; // sure
但它不是通过引用转换或身份转换,而是通过装箱转换(第6.1.7节):
从任何非可空值类型 [...]到由非可空值 类型实现的任何接口类型存在装箱转换。
§13.1.3.2的规则在考虑是否可以进行方差转换时不允许装箱转换,并且没有其他规则可以实现从IEnumerable<int>
到IEnumerable<IComparable<int>>
的隐式转换。 尽管名称如此,隐式转换仍由明确的规则涵盖。
实际上有一个更简单的说明这个问题:
object x = 0; // sure, an int is an object
IEnumerable<object> x = new int[] { 0 }; // except when it's not
出于同样的原因,这是不允许的:没有从int
到object
引用转换,只有一个装箱转换,并且不考虑这些转换。 在这种形式中,Stack Overflow上有几个问题可以解释为什么不允许这样做 (比如这个 )。 总结一下:这不是不可能的 ,但是为了支持它,编译器必须生成支持代码以便在某处粘贴用于装箱转换的代码。 C#团队重视这种情况下的易用性,并决定仅允许保留身份的转换。
最后,作为一个实际考虑的问题,假设您有一个IEnumerable<int>
并且您需要一个IEnumerable<IComparable<int>>
,您将如何获得它? 好吧,自己做拳击:
Func<int, IComparable<int>> asComparable = i => i; // compiles to ldarg ; box ; ret
IEnumerable<IComparable<int>> x = Enumerable.Empty<int>().Select(asComparable);
当然使用Enumerable.Cast
在这里会更实用; 我这样写是为了强调隐含的转换。 这项行动需要付出代价,而这正是重点所在。 C#设计师希望这个成本是明确的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.