[札记]IL经典指令解析之方法调度

call、callvirt和calli指令用于完成方法调用,有何区别呢?

1)call使用静态调度,也就是根据引用类型的静态类型来调度方法。call指令根据引用变量的类型来调用方法,因此通常用于调用非虚方法。

2)callvirt使用虚拟调度,也就是根据引用类型的动态类型来调度方法;callvirt指令根据引用变量指向的对象类型来调用方法,执行时会递归的调用给自己知道堆栈溢出,从而实现了在运行时的动态绑定,因此通常用于调用虚方法。

3)calli又称间接调用,是通过函数指针来执行方法调用的。与call和callvirt相对应的(直接调用)

 Father类

public class Father
    {
        public void DoWork()
        {
            Console.WriteLine("Father.DoWork()");
        }

        public virtual void DoVirtualWork()
        {
            Console.WriteLine("Father.DoVirtualWork()");
        }

        public virtual void DoVirtualAll()
        {
            Console.WriteLine("Father.DoVirtualAll()");
        }
    }

Son类

public class Son:Father
    {
        public static void DoStaticWork()
        {
            Console.WriteLine("Son.DoStaticWork()");
        }

        public new void DoWork()//new表示对父类的阻断
        {
            Console.WriteLine("Son.DoWork()");
        }

        public new virtual void DoVirtualWork()
        {
            Console.WriteLine("Son.DoVirtualWork()");
        }

        public override void DoVirtualAll()
        {
            base.DoVirtualAll();
            Console.WriteLine("Son.DoVirtualAll()");
        }
    }

GrandSon类

public class GrandSon:Son
    {
        public override void DoVirtualWork()
        {
            base.DoVirtualWork();
            Console.WriteLine("GrnadSon.DoVirtualWork()");
        }

        public override void DoVirtualAll()
        {
            base.DoVirtualAll();
            Console.WriteLine("GrandSon.DoVirtualAll()");
        }
    }

Prgram.cs

class Program
    {
        static void Main(string[] args)
        {
            Father son = new Son();
            son.DoWork();
            son.DoVirtualWork();

            Son.DoStaticWork();

            Father aGrandSon = new GrandSon();
            aGrandSon.DoWork();
            aGrandSon.DoVirtualWork();
            aGrandSon.DoVirtualAll();

            Console.ReadLine();
        }
    }

输出结果  

  

IL代码

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 代码大小       61 (0x3d)
  .maxstack  1
  .locals init ([0] class ConsoleApplication1.Father son,
           [1] class ConsoleApplication1.Father aGrandSon)
  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication1.Son::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  callvirt   instance void ConsoleApplication1.Father::DoWork()
  IL_000d:  nop
  IL_000e:  ldloc.0
  IL_000f:  callvirt   instance void ConsoleApplication1.Father::DoVirtualWork()
  IL_0014:  nop
  IL_0015:  call       void ConsoleApplication1.Son::DoStaticWork()
  IL_001a:  nop
  IL_001b:  newobj     instance void ConsoleApplication1.GrandSon::.ctor()
  IL_0020:  stloc.1
  IL_0021:  ldloc.1
  IL_0022:  callvirt   instance void ConsoleApplication1.Father::DoWork()
  IL_0027:  nop
  IL_0028:  ldloc.1
  IL_0029:  callvirt   instance void ConsoleApplication1.Father::DoVirtualWork()
  IL_002e:  nop
  IL_002f:  ldloc.1
  IL_0030:  callvirt   instance void ConsoleApplication1.Father::DoVirtualAll()
  IL_0035:  nop
  IL_0036:  call       string [mscorlib]System.Console::ReadLine()
  IL_003b:  pop
  IL_003c:  ret
} // end of method Program::Main

  

原文地址:https://www.cnblogs.com/xingluzhe/p/4727112.html