Calling methods on value types

半城伤御伤魂 提交于 2019-12-05 12:08:11

Consider an example, suppose we have the following structure:

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

Here's IL code for it:

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

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

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.

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'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.

More on that here and here

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!