对于引用类型,对象的内存布局为
| Type Object pointer|
| Sync Block |
| Instance fields...|
对于值类型,对象布局似乎是
| Instance fields...|
对于引用类型,GetType表示从“类型对象指针”中查找对象。给定引用类型对象的所有对象都指向同一类型对象(也有方法表)
对于值类型,此指针不可用。那么GetType()如何工作?
我查了一下Google,我找到了这个片段..这有点模糊。有人可以详细说明吗?
解决方案是位于 存储的值可能只存储 某种类型的价值观。这是 由验证者保证。 Source
答案 0 :(得分:25)
在值类型的值类型框上调用GetType()
。通过将值类型移动到堆上,您现在拥有一个引用类型,该引用类型现在具有指向该对象类型的指针。
如果你想避免拳击,你可以调用GetTypeCode
,它会返回一个枚举,指示值类型的类型,而无需装箱。
这是一个显示发生拳击的示例:
<强> C#:强>
class Program
{
static void Main()
{
34.GetType();
}
}
IL Main()
:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 8
L_0000: ldc.i4.s 0x22
L_0002: box int32
L_0007: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_000c: pop
L_000d: ret
}
编辑:要显示编译器正在执行的操作,请更改文字的类型,如下所示:
class Program
{
static void Main()
{
34L.GetType();
}
}
通过在文字后添加"L"
我告诉编译器我希望将这个文字转换为System.Int64
。编译器会看到这一点,当它发出box
指令时,它看起来像这样:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 8
L_0000: ldc.i4.s 0x22
L_0002: conv.i8
L_0003: box int64
L_0008: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
L_000d: pop
L_000e: ret
}
正如您所看到的,编译器已经完成了确定要发出的正确指令的艰苦工作,之后由CLR来执行它们。
答案 1 :(得分:5)
也许安德鲁·H认为这很明显,并努力让我理解+1。我的灯泡时刻再次来自Jon Skeet ..这次是通过他的书,我碰巧正在阅读......以及答案所在的确切区域。
考虑下面的代码段。虽然变量类型是BaseRefType,但它指向更专用类型的对象。对于值类型,由于继承是非法的,变量类型是对象的类型。
BaseRefType r = new DerivedRefType();
ValueType v = new ValueType();
我遗失的部分是子弹#1
<Snipped after J.Skeet's comment since it seems to be wrong>
。似乎有一些神奇的东西可以让编译器/运行时知道给定任意变量的'变量类型'。
所以运行时以某种方式知道ob是MyStruct类型,即使VT对象本身没有类型信息。
MyStruct ob = new MyStruct();
ob.WhoAmI(); // no box ; defined in MyStruct
Console.WriteLine(ob.GetHashCode()); // no box ; overridden in ValueType
Console.WriteLine( ob.GetType() ); // box ; implemented in Object
由于这个原因,我能够调用MyStruct(和ValueType中出于某种原因)定义的方法,而无需装箱到RefType。