MSIL入門(二)經過對象看IL

前言

上一篇文章主要介紹了IL的概念以及基礎的示例代碼,在這一篇文章中咱們將經過對象調用看IL。ide

建立對象與調用方法

class Program
{
    static void Main(string[] args)
    {
        var obj = new MyClass();
        Console.WriteLine(obj.Say());
    }
}

class MyClass
{
    private const string Str = "Hello";

    public string Say()
    {
        return Str;
    }
}

實例字段每次建立類型實例的時候都會進行建立,它們屬於這個類型的實例,而靜態字段由類型的全部實例共享,而且它會在類型加載時建立。某些靜態字段(文本字段和映射字段)從不分配。加載程序只須要記錄要映射的字段的位置,並在字段尋址時尋址這些位置。高級別的編譯器(IL assembler不執行此操做,將其會留給咱們開發人員)把實例字段和三種靜態字段中的兩種靜態字段(非文本靜態字段)的類型,很容易從字段標記中識別出引用字段的類型。
當在IL中找到標記時,JIT編譯器沒必要深刻元數據檢索並檢查字段的標誌。此時全部IL有兩組用於字段加載和存儲指令。實例字段的指令爲ldfld,ldflda和stfld;靜態字段的指令是ldsfld,ldsflda和stsfld。嘗試將靜態字段指令與stance字段一塊兒使用會致使JIT編譯失敗。逆向組合是可行的,可是它須要將實例指針加載到堆棧上,這固然對於靜態字段是徹底多餘的。對靜態字段使用實例字段指令的好處是,它容許以相同的方式訪問靜態字段和實例字段。函數

Callvirt 對象調用後期綁定方法,而且將返回值推送到計算堆棧上。this

.field private static literal string Str = "Hello" //靜態公共字段的定義 

.method private hidebysig static void
    Main(
      string[] args
    ) cil managed
  {
    .entrypoint //主函數,程序的入口
    .maxstack 1 //棧的最大深度
    .locals init (
      [0] class ConsoleApp1.MyClass obj //本地變量的定義
    )

    // [8 9 - 8 10]
    IL_0000: nop //什麼都不作

    // [9 13 - 9 37]
    IL_0001: newobj       instance void ConsoleApp1.MyClass::.ctor() //新建類型爲MyClass的對象,並將對象放到堆棧
    IL_0006: stloc.0 //把計算堆棧頂部的值(obj)放到調用堆棧索引0處

    // [10 13 - 10 42]
    IL_0007: ldloc.0      //把調用堆棧索引爲0處的值複製到計算堆棧
    IL_0008: callvirt     instance string ConsoleApp1.MyClass::Say() //調用MyClass.Say方法
    IL_000d: call         void  [System.Console]System.Console::WriteLine(string) //調用WriteLine
    IL_0012: nop //什麼都不作

    // [11 9 - 11 10]
    IL_0013: ret //return 

  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname instance void
    .ctor() cil managed
  {
    .maxstack 8 //棧的最大深度

    IL_0000: ldarg.0 //將索引爲 0 的參數(this)加載到計算堆棧上。
    IL_0001: call         instance void [System.Runtime]System.Object::.ctor() //從堆棧中取出對象,並調用基類(Object)的構造函數
    IL_0006: nop //什麼都不作
    IL_0007: ret //return 

  } // end of method Program::.ctor
class Program
{
    static void Main(string[] args)
    {
        MyClass obj = new MyClass();
        obj.Name = "Hello";
        obj.Say();
    }
}

public class MyClass
{
    public string Name { get; set; }
        
    public void Say()
    {
        Console.WriteLine(Name);
    }
}
.class public auto ansi beforefieldinit
  ConsoleApp1.MyClass
    extends [System.Runtime]System.Object
{

  .field private string '<Name>k__BackingField' //自動生成的字段
    //自動生成獲取屬性值的方法,帶有兩個屬性
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
      = (01 00 00 00 )
    .custom instance void [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Diagnostics.Debug]System.Diagnostics.DebuggerBrowsableState)
      = (01 00 00 00 00 00 00 00 ) // ........
      // int32(0) // 0x00000000 

  .method public hidebysig specialname instance string
    get_Name() cil managed
  {
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
      = (01 00 00 00 )
    .maxstack 8 //棧的最大深度

    // [17 30 - 17 34]
    IL_0000: ldarg.0      //將索引爲 0 的參數(this)加載到計算堆棧上。
    IL_0001: ldfld        string ConsoleApp1.MyClass::'<Name>k__BackingField' //從堆棧取出對象,訪問對象的指定字段,並把字段值存入堆棧
    IL_0006: ret //return 

  } // end of method MyClass::get_Name

  .method public hidebysig specialname instance void
    set_Name(
      string 'value'
    ) cil managed
  {
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
      = (01 00 00 00 )
    .maxstack 8 //棧的最大深度

    // [17 35 - 17 39]
    IL_0000: ldarg.0      //將第一個參數(this)加載到計算堆棧上。
    IL_0001: ldarg.1      //將第二個參數加載到計算堆棧上。
    IL_0002: stfld        string ConsoleApp1.MyClass::'<Name>k__BackingField'
    IL_0007: ret //return 

  } // end of method MyClass::set_Name

  .method public hidebysig instance void
    Say() cil managed
  {
    .maxstack 8 //棧的最大深度

    // [20 9 - 20 10]
    IL_0000: nop //什麼都不作

    // [21 13 - 21 37]
    IL_0001: ldarg.0      //將第一個參數(this)加載到計算堆棧上。
    IL_0002: call         instance string ConsoleApp1.MyClass::get_Name()
    IL_0007: call         void [System.Console]System.Console::WriteLine(string)
    IL_000c: nop //什麼都不作

    // [22 9 - 22 10]
    IL_000d: ret

  } // end of method MyClass::Say

  .method public hidebysig specialname rtspecialname instance void
    .ctor() cil managed
  {
    .maxstack 8

    IL_0000: ldarg.0      // this
    IL_0001: call         instance void [System.Runtime]System.Object::.ctor() 
    IL_0006: nop //什麼都不作
    IL_0007: ret //return 

  } // end of method MyClass::.ctor

  .property instance string Name()
  {
    .get instance string ConsoleApp1.MyClass::get_Name() //標識getter
    .set instance void ConsoleApp1.MyClass::set_Name(string) //標識setter
  } // end of property MyClass::Name
} // end of class ConsoleApp1.MyClass


.method private hidebysig static void
    Main(
      string[] args
    ) cil managed
  {
    .entrypoint //主函數,程序的入口
    .maxstack 2
    .locals init (
      [0] class ConsoleApp1.MyClass obj
    ) //本地變量定義

    // [8 9 - 8 10] 
    IL_0000: nop //什麼都不作

    // [9 13 - 9 41]
    IL_0001: newobj       instance void ConsoleApp1.MyClass::.ctor()  //新建類型爲MyClass的對象,並將對象放到堆棧
    IL_0006: stloc.0      //把計算堆棧頂部的值(obj)放到調用堆棧索引0處 

    // [10 13 - 10 32]
    IL_0007: ldloc.0      //把調用堆棧索引爲0處的值複製到計算堆棧
    IL_0008: ldstr        "Hello" //將字符串"Hello"存入到堆棧
    IL_000d: callvirt     instance void ConsoleApp1.MyClass::set_Name(string) //從堆棧取出對象與參數,並調用對象的指定方法
    IL_0012: nop

    // [11 13 - 11 23]
    IL_0013: ldloc.0      //把調用堆棧索引爲0處的值複製到計算堆棧
    IL_0014: callvirt     instance void ConsoleApp1.MyClass::Say() //調用MyClass.Say方法
    IL_0019: nop //什麼都不作

    // [12 9 - 12 10]
    IL_001a: ret //return 

  } // end of method Program::Main
相關文章
相關標籤/搜索