C#代碼html
class Program { static void Main(string[] args) { string b = GetAge(); Console.ReadKey(); } private static string GetAge() { var a = "a"; var b = "a"; var c = a; return c; } }
使用Reflector 反編譯 IL代碼app
.class private auto ansi beforefieldinit Program extends [mscorlib]System.Object { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void [mscorlib]System.Object::.ctor() L_0006: ret } .method private hidebysig static string GetAge() cil managed { .maxstack 1 .locals init ( [0] string str, [1] string str2, [2] string str3, [3] string str4) L_0000: nop L_0001: ldstr "a" L_0006: stloc.0 L_0007: ldstr "a" L_000c: stloc.1 L_000d: ldloc.0 L_000e: stloc.2 L_000f: ldloc.2 L_0010: stloc.3 L_0011: br.s L_0013 L_0013: ldloc.3 L_0014: ret } .method private hidebysig static void Main(string[] args) cil managed { .entrypoint .maxstack 1 .locals init ( [0] string str) L_0000: nop L_0001: call string ILSample.Program::GetAge() L_0006: stloc.0 L_0007: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() L_000c: pop L_000d: ret } }
關鍵字解釋ide
1. .class中 auto 關鍵字什麼意思?函數
《StructLayout特性》《.net託管環境下struct實例字段的內存佈局(Layout)和大小(Size)》佈局
2. .class中 beforefieldinit 關鍵字什麼意思?
post
這個關鍵字表示讓運行時決定何時調用靜態構造函數,也可能在調用函數的開始處,也可能偏偏在第一次訪問靜態成員或者第一次實例化以前。spa
總之是運行時決定的,只要在你用到這個類以前搞定就行了.net
若是沒有這個關鍵字,則運行時偏偏在第一次訪問靜態成員或者第一次實例化以前調用靜態構造函數。code
至於C#編譯的IL什麼狀況下有這個關鍵字何時沒有關鍵字,判斷起來也很容易,若是有顯式的靜態構造函數,就沒有這個關鍵字,若是沒有顯式的構造函數,就有這個關鍵字。
orm
關於beforefieldinit還有不少有意思的內容,能夠參考下面這些園子裏高手的文章
《關於Type Initializer和 BeforeFieldInit的問題,看看你們可否給出正確的解釋》
《[你必須知道的.NET]第二十三回:品味細節,深刻.NET的類型構造器》
3. .method中 .entrypoint 關鍵字什麼意思?
.entrypoint這個比較簡單,就是程序的入口點,若是是.EXE的程序集有且只能有一個,若是是.DLL的程序集,固然能夠沒有入口點。
C#的Main()函數,就被編譯器加上了.entrypoint,IL編譯器是不認Main()的,只認.entrypoint,因此在IL中,你能夠隨便讓一個函數看成入口。不必非是Main()。
4. .method中 hidebysig 關鍵字什麼意思?
基本至關於C#中的new關鍵字
5. 每一個指令前邊的 IL_00XX: 是神馬東西?
IL_XXXX:其實就是語句的標號,這裏的這些標號是ILDASM生成的,就程序執行來講並無意義。
咱們也能夠根據本身的狀況來寫標號,好比"BEGIN: END:"等等
也能夠經過標號讓程序來跳轉,C#不也是有這個功能的麼?
接下來的問題就是IL_XXXX後便XXXX這幾個數字了,是按什麼編號的?其實很明顯感受是相對於方法入口的地址偏移。
爲了證明這一點,我也沒想到什麼好辦法,隨便寫了一個C#程序,反編譯後爲
IL_0000: ldstr "dddddddddddddddd" //72
IL_0005: call void [mscorlib]System.Console::WriteLine(string) //28
IL_000a: ldstr "ffffffffffffffff" //72
IL_000f: call void [mscorlib]System.Console::WriteLine(string) //28
IL_0014: ldstr "dddddddddddddddd" //72
IL_0019: call void [mscorlib]System.Console::WriteLine(string) //28
IL_001e: ldc.i4.3 //19
IL_001f: stloc.0 //0A
IL_0020: ldc.i4.4 //1A
IL_0021: stloc.1 //0B
IL_0022: ldloc.0 //06
IL_0023: ldloc.1 //07
IL_0024: add //58
IL_0025: stloc.2 //0C
IL_0026: ldloc.2 //08
IL_0027: call void [mscorlib]System.Console::WriteLine(int32) //28
IL_002c: ret //2A
用UltraEdit打開了.EXE文件。
找到這段IL代碼表示二進制代碼(OpCode),查找的方法固然要找到每條指令對應的OpCode,
好比0x72表明ldstr;0x28表明call;0x19表明ldc.i4.3 更多須要參考《MSIL指令\操做\Opcode對照表》
按照內存的順序將列下來,就很容易看出來代碼地址偏移的關係。