反射的妙用:C#通過反射動態生成方法攔截器
阿新 • • 發佈:2021-11-12
在上一篇文章
我們通過反射動態實現並繼承了介面。
這一篇的內容延續上一篇繼續擴充套件:給實現的類新增攔截器。
使用過 MVC 的小夥伴應該都知道 Filter,有請求/異常/返回/認證過濾器,今天我們要實現的攔截器可以理解為 Filter 中的請求過濾器。
實現邏輯:在實現方法主要邏輯之前,呼叫攔截方法。
第一步:先準備攔截器:
public class Intercept { /// <summary> /// 執行之前 /// </summary> /// <param name="methodName"></param> /// <param name="objs"></param> /// <returns></returns> public object Before(string methodName, object[] objs) { Console.WriteLine($"攔截的方法名:{methodName}"); for (int i = 0; i < objs.Length; i++) { Console.WriteLine("這是引數:" + objs[i]); } return "攔截成功"; } }
第二步:在上一篇動態生成的方法中加入呼叫攔截器的程式碼。
// 定義引數集合 var parameters = ilGen.DeclareLocal(typeof(object[])); ilGen.Emit(OpCodes.Ldc_I4, paramType.Length); // 定義新陣列 var arr=new object[](); ilGen.Emit(OpCodes.Newarr, typeof(object)); // 將 parameters 推到棧頂 ilGen.Emit(OpCodes.Stloc, parameters); // 填充引數集合資料 for (var j = 0; j < paramType.Length; j++) { ilGen.Emit(OpCodes.Ldloc, parameters); ilGen.Emit(OpCodes.Ldc_I4, j); // 將下一個值的索引載入到堆疊上 ilGen.Emit(OpCodes.Ldarg, j + 1); // 將對應陣列索引上的值替換 ilGen.Emit(OpCodes.Stelem_Ref); } ilGen.Emit(OpCodes.Ldarg_0); // 定義引數1 ilGen.Emit(OpCodes.Ldstr, targetMethod.Name); // 定義引數2 ilGen.Emit(OpCodes.Ldloc, parameters); // 呼叫攔截函式 ilGen.Emit(OpCodes.Callvirt, typeof(Intercept).GetMethod("Before")); // 判斷是否需要返回值 if (methodBuilder.ReturnType == typeof(void)) { ilGen.Emit(OpCodes.Pop); } else { // 判斷返回型別是否是值型別 if (methodBuilder.ReturnType.IsValueType) { ilGen.Emit(OpCodes.Unbox_Any, methodBuilder.ReturnType); } else { // 強制轉換變數為指定型別(返回值 型別) ilGen.Emit(OpCodes.Castclass, methodBuilder.ReturnType); } }
第三步:呼叫
至此,簡單的動態攔截器就實現成功了。