反映發出動態方法案例
更新:2007 年 11 月
使用 DynamicMethod 類別 (.NET Framework 2.0 版中的新功能) 所建立的動態方法提供了增強型功能,可在執行階段發出靜態方法。動態方法會以數個方式在 System.Reflection.Emit 命名空間中擴充型別的功能:
它們的額外負荷較低,因為不需要產生動態組件、模組和型別來容納方法。
在長期執行的應用程式中,它們會提供較佳的資源利用率,因為可以在不再需要方法時,回收方法主體所用的記憶體。
在有提供足夠的安全性權限之下,它們也提供了將程式碼與現有組件或型別產生關聯的能力,且該程式碼所具備的可視性,可以與內部型別或私用成員相同。
在有提供足夠的安全性權限之下,它們可允許程式碼略過 Just-in-Time (JIT) 可視性檢查,並存取物件的私用和受保護資料。
動態方法可使用 ILGenerator 物件來發出 Microsoft intermediate language (MSIL);此外,動態方法也可使用 DynamicILInfo 物件來處理可讓高階用戶端執行自己的 MSIL 產生作業之中繼資料語彙基元和範圍。
動態方法在因為效能的原因而需要產生執行階段程式碼的情況下會非常實用。本章節內容中所討論的範例包括序列化、物件和關聯式資料庫之間的對應、規則運算式、部分評估,以及需要執行階段的語言編譯器。
如需產生動態方法的簡單範例,請參閱 HOW TO:定義和執行動態方法。
支援晚期繫結呼叫的語言
當物件的型別在編譯時期未知時,動態方法對於編譯器寫入器很有用處。對物件成員的呼叫必須在執行階段解析,這樣通常會產生管理引數清單的額外負荷。下列 Visual Basic 程式碼將提供這個處理的範例。
Sub Example(ByVal obj as Object)
' ...
obj.SomeMethod(x, y, z)
' ...
End Sub
編譯器必須產生程式碼來查詢 SomeMethod、準備引數做為物件的陣列,以及叫用方法。使用 InvokeMember 方法來執行這類具有反映 (Reflection) 的呼叫,並不會提供良好的效能。效能的提升方式,可以藉由使用 System.Reflection.Emit 命名空間的成員來建立動態組件、模組、型別和方法,但是這樣可能會產生較大的工作集,並讓程式碼變得更複雜。動態方法可在動態方法簽章符合現有委派型別的情況下,產生更有效率的實作策略,因為不需要建立動態組件、模組或型別。這個方法的執行效能要比使用 InvokeMember 方法好許多,它的效能雖然不及虛擬呼叫,但是它需要的工作集會小得多,因為不會建立新的型別。此外,不再需要產生的 MSIL 和關聯的機器碼時,也可以將它們回收。
序列化
動態方法可以使得不需要編寫自訂序列化和還原序列化程式碼。您可以根據簡單的規則來標記可序列化的型別,然後使用序列化引擎來檢查此型別的中繼資料、視需要產生適當的序列化程式和還原序列化程式,以及在此型別執行個體上執行產生的程式碼。
在有提供足夠的安全性權限之下,使用動態方法實作的序列化引擎可以存取私用和受保護的資料,以啟用未由引擎建立者所撰寫的物件序列化。
建立的方法如果常用的話,可以快取,或是僅可予以釋放。
部分評估
部分評估 (也稱為程式特製化) 是一種技術,可用在一或多個輸入變數的變化比其他輸入更慢的情況下,讓演算法最佳化。部分評估會產生特定的方法呼叫,這些呼叫會將緩慢變化的輸入值視為常數,讓其他最佳化處理可以整體方式套用到演算法中。
在使用這個技術之後,通常可以將低效能、一般用途的演算法轉換成高效能的特定演算法。下列是一些範例:
編譯 Regex 物件,以產生特製化成符合特定模式的程式。
將中繼資料驅動的序列化引擎編譯成一個程式,此程式是專門用來序列化及還原序列化某特定型別或一組型別。
編譯 XML 結構描述來產生專門用來驗證特定結構描述的程式。
將 XSLT 轉換編譯成專門用來以特定方式轉換 XML 文件的程式。
編譯泛型加密程式,此程式可使用任何指定的金鑰將資料加密成對特定金鑰而言最佳化的程式。
動態方法可用來實作部分評估,其方式是在執行階段產生特定的方法。除了可提高效能之外,動態方法也允許回收 MSIL 方法主體及 JIT 編譯器產生的相關機器碼 (Machine Code);這在長期執行的程式中,可能是很關鍵的一點。
如需這些情況當中一些案例的更詳細描述,請參閱反映發出應用程式案例。
在執行階段產生自訂使用者程式碼
許多應用程式或平台都有一些擴充性機制,可在應用程式執行中時,為使用者提供編寫及執行自訂程式碼的能力 (通常是透過預先定義之函式的使用)。在使用動態方法來產生此程式碼時,應用程式或平台設計工具可減少所需的函式數目 (以及記憶體範圍),並為使用者提供更大的彈性,而不會犧牲效能。