接續《Emit 基本操作》,本文聚焦 ILGenerator 將 IL 指令注入方法體,並完成簡易 Mock 介面動態實作。
.NET 編譯器產生 IL (操作碼/Opcode) 與 CIL 指令 (Directive,如 .assembly, .class, .method)。方法體含 .maxstack、標籤 (Label) 與操作碼 (如 ldstr, call, ret)。計算堆疊遵循「用前壓入、用後彈出」原則,編譯器會優化 .maxstack 大小。
.entrypoint .maxstack 8 IL_0000: nop IL_0001: ldstr "Hello World" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ret
ldstr 壓入字串參考,call 自動彈出堆疊頂作參數呼叫,ret 返回。
.locals init ([0] int32 v1, [1] object v2) IL_0001: ldc.i4.2 IL_0002: stloc.0 IL_0003: ldloc.0 IL_0004: box [mscorlib]System.Int32 IL_0009: stloc.1 IL_000a: ldloc.1 IL_000b: unbox.any [mscorlib]System.Int32 IL_0010: call void [mscorlib]System.Console::WriteLine(int32)
ConstructorBuilder.GetILGenerator()DynamicMethod.GetILGenerator() (無需預建組件/模組/型別)MethodBuilder.GetILGenerator()目標:Mock<IAssessmentAopAdviceProvider> mocker = new Mock<...>(); mocker.Setup(t=>t.Before(3)).Returns("HelloWorld!"); Console.WriteLine(mocker.Obj.Before(2));
核心工廠 AdviceProviderFactory 動態建立型別實作介面:
MethodBuilder mb = typeBuilder.DefineMethod("Before", MethodAttributes.Public|Virtual, typeof(string), new[]{typeof(int)});
ILGenerator gen = mb.GetILGenerator();
LocalBuilder loc = gen.DeclareLocal(typeof(string));
gen.Emit(OpCodes.Nop);
gen.Emit(OpCodes.Ldstr, returnValue); // "HelloWorld!"
gen.Emit(OpCodes.Stloc_0);
gen.Emit(OpCodes.Ldloc_0);
gen.Emit(OpCodes.Ret);
Type t = typeBuilder.CreateType();
assemblyBuilder.Save("test.dll");
return Activator.CreateInstance(t) as IAssessmentAopAdviceProvider;
反組譯驗證產生 IL 符合預期,主控台測試輸出 "HelloWorld!" 成功。
作者:玄魂
出處:https://www.cnblogs.com/xuanhun/