Emit 是反射的孿生兄弟,支援執行期產生 IL 代碼。本系列三篇完成簡易 Mock 介面動態實作,本文為第一篇:建立完整動態組件架構。
業務場景:成對 Before/After 方法依規則分類,工廠 AdviceProviderFactory.GetProvider 動態建立 IAssessmentAopAdviceProvider 實例。單元測試需 Mock 此介面行為,參考 Moq 語法:mock.Setup(t=>t.Before(...)).Returns(...)。
AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run)。Run 僅執行,RunAndSave 可持久化,ReflectionOnly 僅反射。assemblyBuilder.DefineDynamicModule("MvcAdviceProvider"),三個多載支援檔案輸出與符號資訊。moduleBuilder.DefineType(name, TypeAttributes.Public, typeof(object), new[]{typeof(IAssessmentAopAdviceProvider)}) 定義公共類別實作介面。typeBuilder.DefineMethod("Before", MethodAttributes.Public, typeof(object), new[]{typeof(object)}) 定義方法簽章。靜態建構子初始化 AssemblyBuilder/ModuleBuilder;CreateInstance 檢查快取、建立 TypeBuilder、定義 Before/After 方法、CreateType()、Activator.CreateInstance 回傳介面實例。
Mock<T> 持有 Obj (介面實例) 與 SetupContext (記錄 Setup/Returns 設定)。三個擴充方法:Setup 解析 Lambda 取 MethodInfo、Returns 設定回傳值、ToMethodInfo 從運算式樹提取方法。
下篇將注入 IL 方法體完成工廠與 Mock 實際功能,並探討 Emit 與 Mono.Cecil 替代方案。
作者:玄魂
出處:https://www.cnblogs.com/xuanhun/