1988 年 Kernighan 與 Ritchie 合著《The C Programming Language》,Hello, world 成為幾乎所有實踐型程式設計書籍開篇代碼。表達對巨人與歷史尊重,本文以此為起點扣開 IL 語言大門,開始循序漸進的 IL 認識之旅。
using System;
using System.Data;
public class HelloWorld {
public static void Main() {
Console.WriteLine("Hello, world.");
}
}
執行最簡單過程,向世界打招呼。高級語言背後真相是什麼?基於此示例分析 IL 代碼。
對編譯後 HelloWorld.exe 應用 ILDasm.exe 反編譯,還原為文字 MSIL 編碼:

IL 結構包含 MANIFEST 與 HelloWorld 類別。MANIFEST 為附加資訊清單,含組件屬性(名稱、版本、雜湊演算法、模組等)與外部引用組件項目;HelloWorld 類別為主角。

.assembly extern mscorlib:外部載入核心庫 mscorlib;.assembly HelloWorld:定義編譯目標。.assembly 僅顯示程式實際應用的組件清單,using System.Data 若無調用則被忽略,有效避免過度載入導致代碼膨脹。mscorlib.dll 定義 managed code 依賴核心資料型別,屬必載項。.ctor 表建構函數,HelloWorld 無顯式建構函數,繼承自 System.Object(在 mscorlib 中)。.ver)、公開金鑰標記(.publickeytoken,SHA1 雜湊低 8 位元組反序)、語言文化等。.hash algorithm:安全性雜湊演算法,預設 0x00008004(SHA1);.ver:組件版本號。.module:定義模組元資料;imagebase、.file alignment、.subsystem(0x0003 表控制台)、.corflags(預設 1)等非重點指令請參考 MSDN。
.class public auto ansi beforefieldinit HelloWorld
extends [mscorlib]System.Object
{ }
.class:public 類別,繼承 mscorlib 的 System.Object。auto:載入時記憶體配置由 CLR 決定。ansi:非受控與受控代碼間無縫轉換。beforefieldinit:標記 CLR 可在任何時候執行型別建構函數,只要在第一次存取靜態欄位前執行即可,利於效能優化。.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
}
cil managed:方法體為 IL 代碼,編譯為受控代碼。.maxstack:評估堆疊最大資料項數。ldarg.0:載入第一個成員參數(實例方法指當前實例參考),用於基類別建構函數調用。call:調用靜態方法(建構函數在編譯期指定);callvirt 則調用實例方法(執行時確定,檢查虛函數並向下尋找覆寫)。ret:執行完畢返回。.method public hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 8
IL_0000: ldstr "Hello, world."
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret
}
.entrypoint:CLR 載入程式時從此方法開始執行,即程式進入點。每個受控程式必須有且僅有一個進入點。ldstr:字串壓堆,從元資料表獲得字面常數構造 string 物件。未出現 newobj,下回分析。hidebysig:當前類別作為父類別時,方法不被子類別繼承(子類別不見 Main)。去粗取精,簡化 IL 代碼:

註釋展開詳細分析。
從一點角度與 IL 接觸,了解重要指令含義,更重要的是走進 IL 世界。一站式掃描 HelloWorld IL 編碼,不足以全局了解 IL,但首次親密接觸讓我們不再陌生。隨著系列深入將逐漸建立認知,提高掌握 .NET 底層有效工具。後續文章將建立使用工具方法,敬請關注。