Is Richter mistaken when describing the internals of a non-virtual method call?

前端 未结 3 1193
既然无缘
既然无缘 2021-02-07 18:55

I would write this question directly to Jeffrey Richter, but last time he didn\'t answer me :) so I will try to get an answer with your help here, guys :)

In the book \"

3条回答
  •  北海茫月
    2021-02-07 19:47

    As answered by @usr in the similar question I posted How is non-virtual instance method inheritance resolved?:

    Runtime usually means "when/everytime the code runs". The JIT resolution here is only involved once before the code runs. What the JIT does is not being referred to by saying "at runtime".

    Also in Jeffrey's words

    JIT compiler locates the type object that corresponds to the type of the variable being used to make the call.

    The variable type here I believe means "the class specified by the metadata token" (ECMA 335 III.3.19 call) based on which JIT resolves the method destination.

    C# compiler always figures out the correct method to call, and put that info into the metadata token. So JIT never has to "walk down the class hierarchy". (But it can if you manually change the metadata token to an inherited method)

        class A
        {
            public static void Foo() {Console.WriteLine(1); }
            public void Bar() { Console.WriteLine(2); }
        }
        class B : A {}
        class C : B {}
    
        static void Main()
        {
            C.Foo();
            new C().Bar(); 
            C x = new C();
            x.Bar();
            Console.ReadKey();
        }
    
    IL_0000:  call       void ConsoleApplication5.Program/A::Foo() // change to B::Foo()
    IL_0005:  newobj     instance void ConsoleApplication5.Program/C::.ctor()
    IL_000a:  call       instance void ConsoleApplication5.Program/A::Bar() // change to B::Bar()
    IL_000f:  newobj     instance void ConsoleApplication5.Program/C::.ctor()
    IL_0014:  stloc.0
    IL_0015:  ldloc.0
    IL_0016:  callvirt   instance void ConsoleApplication5.Program/A::Bar() // change to B::Bar()
    IL_001b:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_0020:  pop
    IL_0021:  ret
    

    If we use Ildasm + Ilasm to change A::Foo() to B::Foo(), and to change A::Bar() to B.Bar(), the application runs fine.

提交回复
热议问题