取消装箱不会创建值的副本。 这是正确的吗?
我正在阅读微软的Class Room Training Materil。 我读了以下内容
Unboxing Unboxing与拳击相反。 它是将引用类型显式转换为值类型。 取消装箱将检索对象中包含的值类型的引用。 取消装箱操作涉及检查对象实例以确保对象实例是给定值类型的装箱值。 然后,将实例中的值复制到值类型变量中。
**
取消装箱会返回指向装箱对象内数据的指针,而不会创建数据副本。
**
我真的不明白我突出的界限。 它说当拆箱装箱对象时,它不会创建副本,它只返回一个指针。 如果这是真的,那么值类型变量将在Heap中分配吗?
内存
嗯,这是真的,但不是全局。
拆箱本身只返回指向数据的指针,但您无法使用它来访问C#中的数据。 如果在C#中取消装箱值,则始终将其复制到某处。
例:
object o = 42; //box int i = (int)o; //unbox
unboxing iself获取指向对象o
的值42
的指针,然后将值复制到变量i
。
除了Guffa所说的,还有一些额外的信息:
-
您引用的文本描述的“取消装箱”操作描述了
unbox
CIL指令。 关于unbox
,CIL标准有这个说法:与要生成用于对象的值类型的副本所需的
box
不同,unbox
不需要从对象复制值类型。 通常,它只是计算已装箱对象内部已存在的值类型的地址 -
您在C#中使用的拆箱转换不会编译为
unbox
。 它们被编译为另一个名为unbox.any
指令:[…]
unbox.any
指令提取obj (类型O
)中包含的值。 (它相当于unbox
后跟ldobj
。)在英语中,这意味着
unbox.any
执行拆箱操作(unbox
) – 将指针推送到评估堆栈 – 然后是复制操作(ldobj
),它将指针转换为值类型中包含的实际值并推送而是在评估堆栈上。为了完整
ldobj
,这里是ldobj
的描述:ldobj
指令将值复制到评估堆栈。 […] src是一个非托管指针(native int)或托管指针(&)。 […][基本原理:
ldobj
指令可用于传递值类型作为参数。 最终理由 ]
据我所知,C#编译器从不使用unbox
或ldobj
,它总是使用unbox.any
进行拆箱,而ldind.*
用于取消引用引用(例如ref
/ out
参数)。