繁体   English   中英

为什么对值类型的虚拟调用与指向值和盒装值的指针一起使用?

[英]Why virtual calls on value types work with pointers to the value and boxed values?

在下面的示例中,我在值类型( int )上调用虚方法:

namespace ShortTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 42;
            i.ToString();
            ((object)i).ToString();
        }
    }
}

查看Reflector中生成的CIL,我可以看到以下两个调用的代码:

.locals init ([0] int32 i, ...)
...
L_001a: ldloca.s i
L_001c: call instance string [mscorlib]System.Int32::ToString()
L_0021: pop
L_0022: ldloc.0
L_0023: box int32
L_0028: callvirt instance string [mscorlib]System.Object::ToString()
L_002d: pop
...

this参数是第一种情况下int的托管指针,以及第二种情况下对boxed int的引用(即指向带有header字段和int字段的对象的指针)。

由于两个调用使用相同的方法( int实现ToString() ),这怎么办? System.Int32::ToString()方法在this指针上使用ldind.i4来检索int的值,所以它应该在第一种情况下得到int的值,但它应该得到盒装int的值在第二种情况下的第一个字段(标题):

L_0000: ldarg.0
L_0001: ldind.i4
...

但它应该在第二种情况下得到boxed int的第一个字段(标题)的值

您假设ToString方法传递了一个指针,而且恰好指向的字节是读取的内容。 这个假设是错误的。

值类型的实例方法的行为类似于具有ref T “this”参数。 无论值类型是否已装箱,.NET运行时都会确保正确传递,因此该方法不需要为盒装值提供任何特殊处理。

你的出发点是正确的:

I.8.9.7值类型定义

当在值类型上调用非静态方法(即实例或虚方法)时,其this指针是对实例的托管引用,而当在关联的盒装类型上调用该方法时,this指针是对象参考。

但是,这种情况发生的方式是相同的ldind.i4指令无论如何都有效。 只有当它引用非托管指针时,它才会读取字节。

你发现了

II.13.3价值类型的方法

应该对类的实例和虚方法进行编码,以期望对该类的实例的引用作为该指针。 相比之下,值类型的实例和虚方法应编码为期望托管指针(请参阅分区I)到值类型的未装箱实例。 当盒装值类型作为this指针传递给虚拟方法时,CLI应将盒装值类型转换为指向未装箱值类型的托管指针,该方法的实现由未装箱的值类型提供。

乍一看与上述内容相矛盾,但实际上说实施必须简单地使用任何必要的魔法才能使其发挥作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM