泛型在 CLR 中如何表示具體型別參數?本文以 C<T,U,V> 與泛型方法 Test_Method<X,Y> 為例,透過 JIT 反組譯追蹤:泛型類的型別參數陣列掛在 MethodTable 偏移 0x20 處;泛型方法的型別參數則隨呼叫約定以隱藏參數形式壓入堆疊。
class C<T, U, V> where T : class
{
public void Test_Class(V v) { T t = v as T; }
}
C<Type, string, object> c = new C<Type, string, object>();
c.Test_Class(o);
反組譯關鍵路徑:
mov eax, [ebp-3Ch] → thismov eax, [eax] → MethodTablemov eax, [eax+20h] → **GenericParam Info 位址**mov eax, [eax] → 型別參數陣列位址mov eax, [eax] → **T 的 MethodTable** (Type)記憶體佈局驗證:
0x002A3954 0x002A3958 0x6C18172C(Type) 0x6C1808EC(string) 0x6C180508(object) ...
↑ 型別參數陣列起始
!dumpmt 0x6C180508 確認為 System.Object。
public void Test_Method<X, Y>(X x, Y y)
{ Type t1 = typeof(X); Type t2 = typeof(Y); }
c.Test_Method(s, o); // X=string, Y=object
反組譯:
mov eax, [ebp+8] // 參數:GenericParam Table 位址
mov eax, [eax+0Ch] // 偏移 0x0C 為型別參數陣列
mov eax, [eax] // X 的 MethodTable (string)
結論:泛型方法**不**在 MethodTable 儲存型別參數,而是由呼叫端建立 GenericParam Table 並以隱藏參數傳入(x86 通常放在 [EBP+8])。
| 偏移 | 含義 |
|---|---|
| 0x00 | Flags |
| 0x04 | Instance Size |
| 0x14 | Module Address |
| 0x18 | MethodTable End Address |
| 0x1C | EEClass Address (泛型類含義不同) |
| 0x20 | GenericParam Info Address |
| 0x24 | Global Interface Map Table |
| 0x28+ | 虛方法槽位... |