[札記]IL經典指令解析之方法調度

call、callvirt和calli指令用於完成方法調用,有何區別呢?ide

1)call使用靜態調度,也就是根據引用類型的靜態類型來調度方法。call指令根據引用變量的類型來調用方法,所以一般用於調用非虛方法。函數

2)callvirt使用虛擬調度,也就是根據引用類型的動態類型來調度方法;callvirt指令根據引用變量指向的對象類型來調用方法,執行時會遞歸的調用給本身知道堆棧溢出,從而實現了在運行時的動態綁定,所以一般用於調用虛方法。spa

3)calli又稱間接調用,是經過函數指針來執行方法調用的。與call和callvirt相對應的(直接調用)3d

 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類blog

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

輸出結果  ci

  

IL代碼string

 

.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
相關文章
相關標籤/搜索