中繼資料的執行階段使用
若要更了解中繼資料和它在 Common Language Runtime 中的角色,建構簡單程式並說明中繼資料如何影響它的執行階段存留期,可能很有幫助。 下列程式碼範例展示稱為 MyApp 的類別內的兩個方法。 Main 方法為程式進入點,而 Add 方法只是傳回兩個整數引數的總和。
Public Class MyApp
Public Shared Sub Main()
Dim ValueOne As Integer = 10
Dim ValueTwo As Integer = 20
Console.WriteLine("The Value is: {0}", Add(ValueOne, ValueTwo))
End Sub
Public Shared Function Add(One As Integer, Two As Integer) As Integer
Return (One + Two)
End Function
End Class
using System;
public class MyApp
{
public static int Main()
{
int ValueOne = 10;
int ValueTwo = 20;
Console.WriteLine("The Value is: {0}", Add(ValueOne, ValueTwo));
return 0;
}
public static int Add(int One, int Two)
{
return (One + Two);
}
}
當執行程式碼時,Runtime 將模組載入記憶體,並查閱中繼資料以取得這個類別。 一旦載入後,Runtime 會對該方法的 Microsoft Intermediate Language (MSIL) 資料流做一個廣泛的分析,以將它轉換為快速的原生機器指令。 Runtime 使用 Just-in-Time (JIT) 編譯器,按所需一次一個的方法轉換 MSIL 指令至原生機器碼 (Machine Code)。
下列範例展示從前面程式碼的 Main 函式產生的部分 MSIL。 您可以使用 MSIL 反組譯工具 (Ildasm.exe) 來檢視任何 .NET Framework 應用程式中的 MSIL 和中繼資料。
.entrypoint
.maxstack 3
.locals ([0] int32 ValueOne,
[1] int32 ValueTwo,
[2] int32 V_2,
[3] int32 V_3)
IL_0000: ldc.i4.s 10
IL_0002: stloc.0
IL_0003: ldc.i4.s 20
IL_0005: stloc.1
IL_0006: ldstr "The Value is: {0}"
IL_000b: ldloc.0
IL_000c: ldloc.1
IL_000d: call int32 ConsoleApplication.MyApp::Add(int32,int32) /* 06000003 */
JIT 編譯器會讀取整個方法的 MSIL、全面分析它,並產生那個方法的有效率的原生指令。 在 IL_000d 上會遇到 Add 方法的中繼資料語彙基元 (/* 06000003 */),而執行階段即利用語彙基元查閱 MethodDef 表格的第三列。
下表顯示 MethodDef 表格中,由描述 Add 方法的中繼資料語彙基元所參考的部分。 雖然尚有其他中繼資料表存在於這個組件中並擁有其唯一值,但只有這個表格在討論之列。
表格列 |
相關的虛擬位址 (RVA) |
ImplFlags |
旗標 |
名稱 (指向字串堆積) |
簽章 (指向 BLOB 堆積) |
---|---|---|---|---|---|
1 |
0x00002050 |
IL Managed |
Public ReuseSlot SpecialName RTSpecialName .ctor |
.ctor (建構函式) |
|
2 |
0x00002058 |
IL Managed |
Public Static ReuseSlot |
Main |
String |
3 |
0x0000208c |
IL Managed |
Public Static ReuseSlot |
Add |
int, int, int |
表格的每一欄包含您程式碼的重要資訊。 RVA 欄允許執行階段計算定義這個方法的 MSIL 的起始記憶體位址。 ImplFlags 和 Flags 欄包含描述方法的位元遮罩 (例如,方法是否為 Public 或 Private)。 Name 欄對字串堆積中的方法名稱進行索引。 Signature 欄對 BLOB 堆積中方法簽章 (Signature) 的定義進行索引。
Runtime 計算第三列中 RVA 欄的所需位移 (Offset) 位址,並傳回這個位址到 JIT 編譯器,並接著進入新位址。 JIT 編譯器在新位址繼續處理 MSIL 直到遭遇另一個中繼資料語彙基元,並重複這過程。
藉著使用中繼資料,Runtime 擁有對載入您程式碼所需全部資訊的存取權,並處理它成為原生機器指令。 以這個方式,中繼資料允許自我描述檔案和連同一般型別系統的跨語言繼承。