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