我正在阅读CLR specification。我在理解“I 8.2.4拳击和拆箱价值”部分时遇到了一些麻烦。
一方面它声明:
对于每种值类型,CTS定义一个称为盒装类型的相应引用类型。 [...] a的值的表示 盒装类型(盒装值)是可以存储值类型值的位置。盒装类型是 对象类型和盒装值是一个对象。
无法通过名称直接引用盒装类型,因此不能为盒子提供任何字段或局部变量 类型。最接近盒装枚举值类型的命名基类是System.Enum;对于所有其他值类型 它是System.ValueType。键入的字段System.ValueType只能包含空值或a的实例 盒装值类型。键入的本地System.Enum只能包含空值或盒装实例 枚举类型。
这是否意味着我可以拥有使用强类型盒装值类型的属性/方法,或者这只是规范中的遗漏?如果是这样,为什么我可以拥有属性而不是字段?
另一方面,即使在使用MyStruct^
but seems to behave strangely with boxed primitive types(System.Int32^
)的局部变量中,C ++ / CLI似乎也支持盒装值类型。但是我不确定C ++ / CLI编译器魔法的哪一部分(它可能使用标记的Object
变量),哪部分是CLR处理。
该规范进一步指出:
CLS规则3:盒装值类型不符合CLS。 [注意:代替盒装类型,请根据需要使用System.Object,System.ValueType或System.Enum。
这似乎暗示强类型盒装值类型可以是类型的公共接口的一部分。但不应该用于CLS合规性(这是可以理解的,因为大多数语言不支持它们)。
那么在哪里可以使用强类型盒装值类型?为什么它可以用在那些地方,而不是其他地方?
该规范还提到拳击参考类型:
如果类型是以下之一,则该类型是可装箱的:
[...]
引用类型(包括类,数组,委托和泛型类的实例化),不包括 托管指针/ byrefs(§8.2.1.1)
通用参数(通用类型定义或通用方法定义)[注意:拳击和 拆箱通用参数会增加CLI实现的性能开销。受约束。 通过避免,前缀可以在虚拟分派到由值类型定义的方法期间提高性能 装箱值类型。结束说明]
拳击参考类型是否为无操作?允许装箱参考类型对于通用参数很有用,在这些参数中您不知道某些东西是值还是引用类型。因此,我假设装箱参考类型与表示参考类型的通用参数保持一致。
最后我在理解以下段落时遇到了问题:
接口和继承仅在引用类型上定义。因此,虽然值类型定义(第8.9.7节)可以 指定两个应由值类型和类实现的接口(System.ValueType或 它继承的System.Enum),仅适用于盒装值。
“在类型上定义”的界面是什么意思?我的理解是,转换为接口/基类会对值进行处理,但您仍然可以使用受约束的虚拟调用来调用未装箱的此类接口/类中定义的方法。 (带有约束前缀的virtcall)
答案 0 :(得分:4)
是的,C ++ / CLI语言允许声明强类型的盒装值类型:
public ref class Class1
{
public:
int^ boxedInt;
Class1() { boxedInt = 42; }
};
它遵守CLI规范,但 boxedInt 字段在元数据中键入ValueType。它记住并检查带有modOpt属性的盒装类型:
field boxedInt: public class System.ValueType modopt(System.Int32) modopt(System.Runtime.CompilerServices.IsBoxed)
在C#中可能完全相同,减去编译器检查只有int值被赋给字段。只需将该字段声明为ValueType即可。否则这没有实际价值。