每从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中的泛型类型背后的机制不能用于这种类型。
但Int32可以转换为Object。这不足以作出协变吗?或者它是一个编译器功能? – Vasaka
@Vasaka:这是一个装箱操作,而不是参考转换。这是技术性的,但是尽管编译器在每种情况下都具有相同的语法,但完全不同。 – Jon
...正如所有泛型类和结构的类型参数一样;仅支持接口和委托类型的类型差异。 – phoog