首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 泛型型別參數運行時存儲機制:泛型類存在 MethodTable,泛型方法透過參數傳遞

     編輯:關於.NET

泛型在 CLR 中如何表示具體型別參數?本文以 C<T,U,V> 與泛型方法 Test_Method<X,Y> 為例,透過 JIT 反組譯追蹤:泛型類的型別參數陣列掛在 MethodTable 偏移 0x20 處;泛型方法的型別參數則隨呼叫約定以隱藏參數形式壓入堆疊。

泛型類:MethodTable 內嵌 GenericParam Info

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);

反組譯關鍵路徑:

  1. mov eax, [ebp-3Ch] → this
  2. mov eax, [eax] → MethodTable
  3. mov eax, [eax+20h] → **GenericParam Info 位址**
  4. mov eax, [eax] → 型別參數陣列位址
  5. mov eax, [eax] → **T 的 MethodTable** (Type)

記憶體佈局驗證:

0x002A3954  0x002A3958  0x6C18172C(Type)  0x6C1808EC(string)  0x6C180508(object) ...
           ↑ 型別參數陣列起始

!dumpmt 0x6C180508 確認為 System.Object。

泛型方法:隱藏參數傳遞 GenericParam Table

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])。

MethodTable 關鍵偏移記錄(.NET 2.0)

偏移含義
0x00Flags
0x04Instance Size
0x14Module Address
0x18MethodTable End Address
0x1CEEClass Address (泛型類含義不同)
0x20GenericParam Info Address
0x24Global Interface Map Table
0x28+虛方法槽位...

總結

  • 泛型類:型別參數**靜態**存於 MethodTable,實例化時固定;
  • 泛型方法:型別參數**動態**隨呼叫傳遞,同一方法不同實例化共用代碼;
  • 這也是為何泛型類每個封閉型別有獨立 MethodTable,泛型方法僅有一份代碼的原因。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved