[英]Generics type casting
我只是在.NET泛型类型转换中没有得到什么。 有人可以解释下面的代码片段中会发生什么吗?
void Main()
{
IEnumerable<int> ints = new List<int>();
IEnumerable<string> strings = new List<string>();
var rez1=(IEnumerable<object>)ints; //runtime error
var rez2=(IEnumerable<object>)strings; //works
var rez3=(List<object>)strings; //runtime error
}
让我们从第二行开始,这是最简单的。
这铸作品,因为类型参数IEnumerable<T>
现在是协变 (这是什么out
在out T
一样)。 这意味着您可以自由地将IEnumerable<Derived>
转换为IEnumerable<Base>
。
第一行似乎是相同的情况,因为int
是值类型,所以不起作用。 接口方差根本不适用于值类型,因为值类型并不真正从System.Object
继承; 它们可以被装箱到object
,但是这是不一样的。 文件提到了这一点
差异仅适用于参考类型; 如果为变量类型参数指定值类型,则该类型参数对于生成的构造类型是不变的。
最后,第三行不起作用,因为List<T>
的类型参数是不变的 。 你可以看到它的类型参数没有out
; 规则不允许因为List<T>
不是接口:
在.NET Framework 4中,变体类型参数仅限于通用接口和通用委托类型。
这是因为界面协方差仅适用于引用类型。 当然,Int32是一种值类型。
这提供了更多信息: http : //blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx
这样做: http : //ericlippert.com/2011/09/19/inheritance-and-representation/
从System.ValueType
派生的每个类型的定义( System.Enum
除外)实际上定义了两种类型:堆对象类型和存储位置类型。 后者的实例可以隐式转换为前者(制作其中包含的数据的副本),前者的实例可以明确地对后者进行类型转换(同样); 即使两种事物都由相同的System.Type
描述,虽然它们具有相同的成员,但它们的行为却截然不同。
List<AnyClassType>
将包含一堆堆对象引用; 有问题的列表是List<String>
, List<StringBuilder>
, List<Button>
还是其他,列表的用户可能会感兴趣,但List<T>
本身并不感兴趣。 如果将List<Button>
转换为IEnumerable<Control>
,则调用其GetEnumerator()
方法的人将期望获得一个对象,该对象将输出对从Control
派生的堆对象的引用; List<Button>.GetEnumerator()
的返回将满足该期望。 相比之下,如果有人将List<Int32>
为List<Object>
,那么调用GetEnumerator()
会期望输出堆对象引用的东西,但List<Integer>.GetEnumerator
会产生输出值的东西 -类型整数。
可以将Int32
值存储到List<Object>
或List<ValueType>
; 将整数存储到这样的列表中会将其转换为堆对象形式并存储对它的引用; 调用GetEnumerator()
会产生输出堆引用的东西。 但是,无法指定此类列表仅包含与Int32
对应的堆类型的实例。 在C ++ / CLI中,可以声明“对堆存储的值类型的引用”类型的变量,但.net中泛型类型背后的机制不能用于这些类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.