值类型的调用方法 [英] Calling methods on value types

查看:81
本文介绍了值类型的调用方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我在这里犯了一个错误,请停止我.

Stop me if I make a mistake here.

如果我理解正确,那么当我在类的实例上调用方法时,JIT编译器会找到与该实例的类型相对应的类型对​​象,然后在其中找到对实际方法代码的引用.

If I understand correctly, when I call a method on an instance of a class, the JIT compiler locates the type object corresponding to the type of the instance and then locates a reference therein to the actual method code.

我的问题是这对值类型如何起作用?我的印象是值类型不像引用类型那样具有类型对象指针.如果是这种情况,当调用CLR时,CLR如何设法导航到方法代码?

My question is how does this work for value types? I was under the impression that value types did not have a type object pointer like reference types do. If this is the case, how does the CLR manage to navigate to the method code when one is called?

推荐答案

考虑一个示例,假设我们具有以下结构:

Consider an example, suppose we have the following structure:

public struct Test
{
    public void TestMethod()
    {            
    }
}

这是它的IL代码:

.class public sequential ansi sealed beforefieldinit ConsoleApplication.Test
    extends [mscorlib]System.ValueType
{
    .pack 0
    .size 1

    .method public hidebysig 
        instance void TestMethod () cil managed 
    {
        // Method begins at RVA 0x21dc
        // Code size 1 (0x1)
        .maxstack 8

        IL_0000: ret
    } // end of method Test::TestMethod

}

好吧,现在因为C#编译器静态知道Test的类型,所以它可以进行重载解析并找到确切的TestMethod被调用.然后,它发出MSIL,将参数推送到MSIL虚拟堆栈上,并期待指向Test的类型指针参数,编译器无需装箱即可处理该参数,并发出包含对该特定方法的元数据引用的调用指令.

Ok, now because the C# compiler statically knows the type of Test, it can do overload resolution and find the exact TestMethod being called. Then it emits MSIL to push the arguments onto the MSIL virtual stack, it expects a parameter of type pointer to Test, which the compiler handles without boxing and issues a call instruction containing a metadata reference to that particular method.

.locals init (
        [0] valuetype ConsoleApplication.Test test
    )

IL_0000: ldloca.s test
IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloca.s test
IL_000a: call instance void ConsoleApplication.Test::TestMethod()

对于ToStringGetHashCode,编译器使用约束的OpCode ,因为这些方法可以重载.

For ToString and GetHashCode the compiler uses the Constrained OpCode, because these methods can be overloaded.

IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloca.s test
IL_000a: constrained. ConsoleApplication.Test
IL_0010: callvirt instance int32 [mscorlib]System.Object::GetHashCode()

受约束的操作码允许IL编译器调用虚拟 与ptr是否为值类型无关,以统一的方式起作用 或参考类型.使用受约束的前缀也可以避免 值类型的潜在版本控制问题.如果被约束 不使用前缀,取决于是否发出不同的IL 值类型是否覆盖System.Object的方法.例如, 如果值类型V覆盖Object.ToString()方法,则调用 V.ToString()指令被发出;如果没有,则显示一个框指令 并发出callvirt Object.ToString()指令.一种 如果覆盖是 后来删除,并且在后一种情况下(如果以后添加了覆盖).

The constrained opcode allows IL compilers to make a call to a virtual function in a uniform way independent of whether ptr is a value type or a reference type. Using the constrained prefix also avoids potential versioning problems with value types. If the constrained prefix is not used, different IL must be emitted depending on whether or not a value type overrides a method of System.Object. For example, if a value type V overrides the Object.ToString() method, a call V.ToString() instruction is emitted; if it does not, a box instruction and a callvirt Object.ToString() instruction are emitted. A versioning problem can arise in the former case if the override is later removed, and in the latter case if an override is later added.

对于GetType方法,需要装箱,因为它是非虚拟的并且以Object类型定义.

For the GetType method requires boxing because it's non-virtual and defined in the Object type.

IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloc.0
IL_0009: box ConsoleApplication.Test
IL_000e: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()

这篇关于值类型的调用方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆