编程语言
首页 > 编程语言> > 反射的妙用: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);
		}
	}

第三步:调用

image

image

image

至此,简单的动态拦截器就实现成功了。

无绪分享

标签:反射,ilGen,拦截器,parameters,C#,object,OpCodes,Emit
来源: https://www.cnblogs.com/cool-net/p/15543952.html