ValueType.GetType()如何确定结构的类型?

Gis*_*shu 28 .net c# types

对于引用类型,对象的内存布局是

| Type Object pointer|
|    Sync Block      |
|  Instance fields...|
Run Code Online (Sandbox Code Playgroud)

对于值类型,对象布局似乎是

|  Instance fields...|
Run Code Online (Sandbox Code Playgroud)

对于引用类型,GetType表示从"类型对象指针"中查找对象.给定引用类型对象的所有对象都指向同一类型对象(也有方法表)

对于值类型,此指针不可用.那么GetType()如何工作?

我查了一下谷歌,我发现了这个片段..这有点模糊.有人可以详细说明吗?

解决方案是存储值的位置可以仅存储特定类型的值.这由验证者保证. 资源

And*_*are 25

调用GetType()值类型的值类型框.通过将值类型移动到堆上,您现在拥有一个引用类型,该类型现在具有指向该对象类型的指针.

如果你想避免装箱,你可以调用GetTypeCode哪个返回一个枚举,指示值类型的类型而不用装箱.

这是一个显示拳击发生的例子:

C#:

class Program
{
    static void Main()
    {
        34.GetType();
    }
}
Run Code Online (Sandbox Code Playgroud)

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 
}
Run Code Online (Sandbox Code Playgroud)

编辑:要显示编译器正在做什么,让我们改变文字的类型,如下所示:

class Program
{
    static void Main()
    {
        34L.GetType();
    }
}
Run Code Online (Sandbox Code Playgroud)

通过"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 
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,编译器已经完成了确定要发出的正确指令的艰苦工作,之后由CLR来执行它们.


Gis*_*shu 5

也许Andrew H.认为这很明显,并努力让我理解+1.我的灯泡时刻再次来自Jon Skeet ..这次是通过他的书,我碰巧正在阅读......以及答案所在的确切区域.

  • C#是静态类型的.每个变量都有一个类型,它在编译时是已知的.
  • 值类型不能继承.因此,VT对象不需要携带额外的类型信息(与Ref Type对象相反,每个对象都有一个对象类型标题,因为变量类型和值/对象类型可能不同.)

考虑下面的代码段.虽然变量类型是BaseRefType,但它指向更专用类型的对象.对于值类型,由于继承是非法的,因此变量类型对象的类型.

BaseRefType r = new DerivedRefType(); 
ValueType v = new ValueType();
Run Code Online (Sandbox Code Playgroud)

我失踪的是子弹#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
Run Code Online (Sandbox Code Playgroud)

因此,我能够调用MyStruct(和ValueType中出于某种原因)定义的方法,而无需装入RefType.

  • 我不能说我是这里的具体细节的专家,但我建议你看一下IL规范(ECMA-335),特别是"受约束"的操作码.这就是允许在没有拳击的情况下调用虚拟方法的原因,我相信.(编译调用GetHashCode()和GetType()的代码.话虽如此,你关于它是两个指针的想法也是错误的.r的值是对象的引用,对象本身具有对其实际类型的引用.v的值只是变量的值,但编译器和运行时无论如何都知道确切的类型(由于缺少值类型继承) (2认同)