動態編譯雖強,若每次調用仍靠 MethodInfo.Invoke 反射,效能優勢盡失。本文揭示關鍵技巧:**將靜態方法改為實例方法、實作共用介面、編譯後轉型為介面實例、快取介面直接調用**,實測 100 萬次循環下 **快 10 倍以上**(330ms → 24ms),甚至超越 Newtonsoft.Json。
動態編譯的類別名稱是運行時產生的(如 _336090f4e7724d2585b07e79210decb4),編譯期無法寫死 ClassName.Method(),只能透過反射 Invoke。
namespace blqw {
public interface IGetString {
string GetString(object obj);
}
}
// 改造前(靜態)
public class _xxx {
public static string A(User obj) { /* ... */ }
}
// 改造後(實例 + 介面)
public class _xxx : blqw.IGetString {
public string GetString(object o) {
User obj = (User)o;
/* ... 建構 JSON 字串 ... */
}
}
// 編譯
var ass = DynamicCompile_1.CompileAssembly(code, ...);
// 實例化並轉介面(僅第一次需反射)
var getter = (IGetString)ass.GetTypes()[0]
.GetConstructor(Type.EmptyTypes)
.Invoke(null);
// 快取 getter
MethodCache[type] = getter;
// 後續調用:零反射
return getter.GetString(user); // 純虛擬呼叫,極快
// 反射調用靜態方法
var met = typeof(Program).GetMethod("A");
for (int i=0; i<1_000_000; i++) met.Invoke(null, new[] { user });
// 330ms 級
// 介面實例調用
var getter = (IGetString)Activator.CreateInstance(typeof(Program));
for (int i=0; i<1_000_000; i++) getter.GetString(user);
// 24ms 級
結果:
333ms | 25ms 330ms | 24ms 326ms | 24ms ... (10次皆穩定 10倍以上差距)
純反射 10000次 x10: 168 | 153 | 152 | 152 | 154 | 157 | 157 | 158 | 158 | 153 ms 動態編譯+介面 10000次 x10: 222 | 116 | 118 | 117 | 113 | 109 | 105 | 106 | 105 | 107 ms Newtonsoft.Json 10000次 x10: 359 | 177 | 192 | 182 | 188 | 189 | 189 | 189 | 187 | 189 ms
動態編譯 + 介面快取 **穩定擊敗 Newtonsoft.Json**,且輸出格式完全一致。

Dictionary<Type, IGetString> 確保每型別只編譯/實例化一次。GetString(object),內部再 cast 回具體型別。下一篇將把這套機制封裝進 DynamicCompile 庫,並展示如何自動為任意型別生成 IGetString 實作代碼,實現真正的「一鍵加速」。