阅读ValueTypes - RefTypes - EricLippert后,我有3个问题:
因为假设'int'派生自System.ValueType,派生自System.Object,
那么'int'这样的值类型确实占用了多少空间(看到它最终来自System.Object)? 它只是int的大小或用于区分它是值类型的额外CLR簿记字段。
'int'和'object'之间的大小差异?
当'int'用包装器装箱时。那么包装器只是一个对象类型(和 对象转到堆)的情况呢?这个包装器对象和普通新对象()之间的区别?包装器会产生多大的尺寸/空间?
答案 0 :(得分:6)
int
是32位,无论如何,因为它是值。
Object
部分只有在您装入它时才会发挥作用(例如在C#中将其转换为object
)。一旦发生这种情况,就会使用对象拥有的所有内容创建一个新对象,并在该对象内部驻留您的int。
这就是为什么C#泛型与Java相比如此惊人,因为您不会将值类型强制转换为对象只是为了将它们放在通用容器中,因此值类型实际上是整个时间的值类型(或直到程序员变得懒惰并开始抛出object val=...
。
编辑:我可以理解这种困惑,因为他们对编译器的工作有多么惊人:
var s=12.GetType(); // if it looks like an object and walks like an object...
但它是不是一个对象,直到GetType
调用,此时值被装入一个对象并在其上调用虚方法。
从ValueType
派生的Object
也是如此。只是编译器忽略的一些非常复杂的语法糖,并在你的背后做了奇怪的事情:)
edit2:这是显示拳击的消解代码:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] class [mscorlib]System.Type s)
L_0000: nop
L_0001: ldc.i4.s 12
L_0003: box int32 // <---
L_0008: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_000d: stloc.0
L_000e: ldloc.0
L_000f: call void [mscorlib]System.Console::WriteLine(object)
L_0014: nop
L_0015: ret
}