1. 程式人生 > 其它 >反射的妙用:C#通過反射動態生成方法攔截器

反射的妙用:C#通過反射動態生成方法攔截器

在上一篇文章

反射的妙用:C#通過反射動態生成型別繼承介面並實現

我們通過反射動態實現並繼承了介面。

這一篇的內容延續上一篇繼續擴充套件:給實現的類新增攔截器

使用過 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);
		}
	}

第三步:呼叫

至此,簡單的動態攔截器就實現成功了。

無緒分享