.net 装箱的CLR规范

.net 装箱的CLR规范,.net,c++-cli,clr,value-type,boxing,.net,C++ Cli,Clr,Value Type,Boxing,我现在正在看报纸。我在理解“I 8.2.4值的装箱和拆箱”部分时有点困难 1.何时可以使用盒装类型? 一方面,它指出: 对于每个值类型,CTS都定义了一个相应的引用类型,称为装箱类型。[…]表示某个值的值 装箱类型(装箱值)是可以存储值类型的值的位置。盒装字体是一种特殊的字体 对象类型和装箱值是对象 装箱类型不能通过名称直接引用,因此不能为任何字段或局部变量指定装箱类型 类型。最接近装箱枚举值类型的命名基类是System.Enum;对于所有其他值类型 它是System.ValueType。Sys

我现在正在看报纸。我在理解“I 8.2.4值的装箱和拆箱”部分时有点困难

1.何时可以使用盒装类型? 一方面,它指出:

对于每个值类型,CTS都定义了一个相应的引用类型,称为装箱类型。[…]表示某个值的值 装箱类型(装箱值)是可以存储值类型的值的位置。盒装字体是一种特殊的字体 对象类型和装箱值是对象

装箱类型不能通过名称直接引用,因此不能为任何字段或局部变量指定装箱类型 类型。最接近装箱枚举值类型的命名基类是System.Enum;对于所有其他值类型 它是System.ValueType。System.ValueType类型的字段只能包含null值或 装箱值类型。Locals类型化System.Enum只能包含null值或已装箱文件的实例 枚举类型

这是否意味着我可以拥有使用强类型装箱值类型的属性/方法,或者这只是规范中的一个遗漏?如果是,为什么我可以有属性而没有字段

另一方面,C++/CLI似乎支持装箱值类型,即使在使用
MyStruct^
的局部变量中也是如此。但我不确定这其中的哪一部分是C++/CLI编译器魔法(它可能会使用标记的
对象
变量),以及哪一部分是CLR处理的

该规范进一步规定:

CLS规则3:装箱的值类型不符合CLS。 [注意:使用System.Object、System.ValueType或System.Enum(视情况而定)代替装箱类型

这似乎意味着强类型装箱值类型可以是类型的公共接口的一部分,但不应用于CLS遵从性(这是可以理解的,因为大多数语言不支持它们)

那么,在哪里可以使用强类型盒式值类型呢?为什么在这些地方可以使用它,而在其他地方却不能

2.装箱引用类型 规范还提到了装箱引用类型:

如果类型是以下类型之一,则该类型是可装箱的:

[……]

  • 引用类型(包括类、数组、委托和泛型类的实例化),不包括 托管指针/字节引用(§8.2.1.1)

  • 泛型参数(泛型类型定义或泛型方法定义)[注:装箱和 取消装箱泛型参数会增加CLI实现的性能开销。 前缀可以在虚拟分派到由值类型定义的方法期间通过避免 装箱值类型。结束注释]

装箱引用类型是否为无操作?如果您不知道某个对象是值还是引用类型,则允许装箱引用类型对泛型参数很有用。因此,我假设装箱引用类型是为了与表示引用类型的泛型参数保持一致

3.接口“定义在类型上”的含义是什么? 最后,我在理解以下段落时遇到问题:

接口和继承仅在引用类型上定义。因此,值类型定义(§8.9.7)可以 指定应通过值类型和类实现的两个接口(System.ValueType或 枚举),这些值仅适用于已装箱的值


“在类型上定义”接口的含义是什么?我的理解是,对接口/基类的强制转换会限制值,但您仍然可以使用受约束的虚拟调用在未绑定的对象上调用在此类接口/类中定义的方法。(带约束前缀的virtcall)

是的,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。否则就没有实际价值。

关于最后一个问题,我认为混淆源于这样一个事实,即CIL中没有“强制转换”。在C#中强制转换(或其他托管语言)可以转换为各种CIL操作,其中之一是装箱。不过,我不确定接口方法。如果有一个名为
obj
Object^
,包含对装箱
Int32
的引用,则可以使用
*((Int32^)Object)=5;
导致装箱对象的值将为5。尽管.net假装拥有“统一类型系统”,装箱任何值类型都会将其转换为可变引用类型,并使用
Equals
方法假定其永远不会发生变异。