简体   繁体   English

调用值类型的方法

[英]Calling methods on value types

Stop me if I make a mistake here. 如果我在这里弄错了,请阻止我。

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. 如果我理解正确,当我在类的实例上调用方法时,JIT编译器将找到与实例类型相对应的类型对​​象,然后在其中找到实际方法代码的引用。

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? 如果是这种情况,CLR如何在调用方法时设法导航到方法代码?

Consider an example, suppose we have the following structure: 考虑一个例子,假设我们有以下结构:

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

Here's IL code for it: 这是它的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

}

Ok, now because the C# compiler statically knows the type of Test , it can do overload resolution and find the exact TestMethod being called. 好的,现在因为C#编译器静态地知道Test的类型,它可以进行重载解析并找到被调用的确切TestMethod 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. 然后它发出MSIL以将参数推送到MSIL虚拟堆栈,它需要一个指向Test的类型指针的参数,编译器在没有装箱的情况下处理它并发出包含对该特定方法的元数据引用的调用指令。

.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()

For ToString and GetHashCode the compiler uses the Constrained OpCode , because these methods can be overloaded. 对于ToStringGetHashCode ,编译器使用Constrained OpCode ,因为这些方法可以重载。

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

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. 受约束的操作码允许IL编译器以统一的方式调用虚函数,而与ptr是值类型还是引用类型无关。 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. 如果未使用约束前缀,则必须发出不同的IL,具体取决于值类型是否覆盖System.Object的方法。 For example, if a value type V overrides the Object.ToString() method, a call V.ToString() instruction is emitted; 例如,如果值类型V覆盖Object.ToString()方法,则会发出调用V.ToString()指令; if it does not, a box instruction and a callvirt Object.ToString() instruction are emitted. 如果没有,则发出一个box指令和一个callvirt Object.ToString()指令。 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. 如果稍后删除覆盖,则在前一种情况下可能出现版本控制问题,而在后一种情况下,如果稍​​后添加覆盖则会出现版本控制问题。

For the GetType method requires boxing because it's non-virtual and defined in the Object type. 对于GetType方法需要装箱,因为它是非虚拟的并且在Object类型中定义。

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's called boxing or auto-boxing, the CLR will automatically instantiate the corresponding class from a value type if you call some method on it. 它被称为装箱或自动装箱,如果您在其上调用某个方法,CLR将自动从值类型实例化相应的类。

More on that here and here 更多关于这里这里

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

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