C# 使用Emit实现动态AOP框架 进阶篇之异常处理

     目  录

C# 使用Emit实现动态AOP框架 (一)

C# 使用Emit实现动态AOP框架 (二)

C# 使用Emit实现动态AOP框架 (三)

C# 使用Emit实现动态AOP框架 进阶篇之异常处理

C# 使用Emit实现动态AOP框架 进阶篇之优化

通过特性处理异常,也是AOP的一个功能。

  • 定义异常处理特性AspectExceptionAttribute

       该类也是继承了切面特性基类AspectAttribute

 1  public class AspectExceptionAttribute : AspectAttribute
 2   {
 3         public override InterceptType InterceptType { get; set; }
 4 
 5         public override void OnEntry(AspectContext context)
 6         {
 7             if (context != null)
 8             {
 9                 if (context.Result != null && context.Result is Exception)
10                 {
11                     Console.WriteLine("Exception : " + context.Name + " " + (context.Result as Exception).Message);
12                 }
13             }
14  
15         }
16 
17         public override void OnExit(AspectContext context)
18         {
19             if (context != null)
20             {
21                 Console.WriteLine("Finally  : " + context.Name);
22             }
23         }

 

  • 在ILGenerateProxyMethod方法中加入异常处理代码

    Emit异常处理代码主要由BeginExceptionBlock,BeginCatchBlock,BeginFinallyBlock,EndExceptionBlock组成;

     进行异常处理前,先申明 AspectExceptionAttribute对象,即  AspectExceptionAttribute aspectExceptionAttribute = new AspectExceptionAttribute(); 其对应Emit代码如下:

 1             //获取异常处理类型
 2             var aspectExceptionType = typeof(AspectExceptionAttribute);
 3 
 4             //申明一个异常处理特性对象
 5             var aspectExceptionAttribute = il_ProxyMethod.DeclareLocal(aspectExceptionType);
 6 
 7             //获取其构造函数
 8             ConstructorInfo temp = aspectExceptionType.GetConstructor(Type.EmptyTypes);
 9 
10             //生成一个新对象
11             il_ProxyMethod.Emit(OpCodes.Newobj, temp);
12 
13             //存储到 aspectExceptionAttribute
14             il_ProxyMethod.Emit(OpCodes.Stloc, aspectExceptionAttribute);

Catch时触发aspectExceptionAttribute.OnEntry();Finally时调用 aspectExceptionAttribute.OnEixt();对应Emit代码如下:

1 //加载异常特性对象                
2 il_ProxyMethod.Emit(OpCodes.Ldloc,aspectExceptionAttribute);
3 //加载参数 4 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); 5 //调用OnEntry方法 6 il_ProxyMethod.Emit(OpCodes.Callvirt, aspectExceptionType.GetMethod("OnEntry"));

Catch调用OnEntry前,还要将捕获到的Exception对象赋值给aspectContext的Result属性;即 aspectContext.Result = ex; 对应Emit代码如下:

1  LocalBuilder exception = il_ProxyMethod.DeclareLocal(typeof(Exception));
2 
3  il_ProxyMethod.Emit(OpCodes.Stloc, exception);
4 
5  //复制Exception到Result
6  il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
7  il_ProxyMethod.Emit(OpCodes.Ldloc, exception);//错误信息
8  il_ProxyMethod.Emit(OpCodes.Box, typeof(Exception));
9  il_ProxyMethod.Emit(OpCodes.Call, typeof(AspectContext).GetMethod("set_Result"));//赋值

完整的ILGenerateProxyMethod的方法如下:

  1       private static void ILGenerateProxyMethod(ILGenerator il_ProxyMethod, MethodInfo src_Method, Type[] paramTypes, object[] aspectAttributes)
  2         {
  3             int aspectCount = aspectAttributes.Length;
  4 
  5             //生成切面上下文
  6             LocalBuilder aspectContext = CreateAspectContext(il_ProxyMethod, src_Method.Name, paramTypes);
  7 
  8             //申明临时存放切面对象和OnExit方法的变量
  9             var aspectLocalBuilders = new LocalBuilder[aspectCount];
 10             var onExit_Methods = new MethodInfo[aspectCount];
 11 
 12  
 13             //获取异常处理类型
 14             var aspectExceptionType = typeof(AspectExceptionAttribute);
 15 
 16             //申明一个异常处理特性对象
 17             var aspectExceptionAttribute = il_ProxyMethod.DeclareLocal(aspectExceptionType);
 18 
 19             //获取其构造函数
 20             ConstructorInfo temp = aspectExceptionType.GetConstructor(Type.EmptyTypes);
 21 
 22             //生成一个新对象
 23             il_ProxyMethod.Emit(OpCodes.Newobj, temp);
 24 
 25             //存储到 aspectExceptionAttribute
 26             il_ProxyMethod.Emit(OpCodes.Stloc, aspectExceptionAttribute);
 27 
 28             Label tryLabel = il_ProxyMethod.BeginExceptionBlock();//对应Try
 29 
 30             //初始化标记的切面对象,并调用切面对象的OnEntry方法
 31             for (int i = 0; i < aspectCount; i++)
 32             {
 33                 //创建一个切面对象
 34                 var aspectType = aspectAttributes[i].GetType();
 35                 var aspect = il_ProxyMethod.DeclareLocal(aspectType);
 36                 ConstructorInfo constructor = aspectType.GetConstructor(Type.EmptyTypes);
 37 
 38                 il_ProxyMethod.Emit(OpCodes.Newobj, constructor);
 39                 il_ProxyMethod.Emit(OpCodes.Stloc, aspect);
 40 
 41                 var onEntry_method = aspectType.GetMethod("OnEntry");
 42                 onExit_Methods[i] = aspectType.GetMethod("OnExit");
 43 
 44                 //调用OnEntry
 45                 il_ProxyMethod.Emit(OpCodes.Ldloc, aspect);
 46                 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
 47                 il_ProxyMethod.Emit(OpCodes.Callvirt, onEntry_method);
 48                 il_ProxyMethod.Emit(OpCodes.Nop);
 49 
 50                 aspectLocalBuilders[i] = aspect;
 51             }
 52 
 53             //类对象,参数值依次入栈
 54             for (int i = 0; i <= paramTypes.Length; i++)
 55                 il_ProxyMethod.Emit(OpCodes.Ldarg, i);
 56 
 57             //调用基类的方法
 58             il_ProxyMethod.Emit(OpCodes.Call, src_Method);
 59 
 60 
 61             //定义返回值
 62             LocalBuilder result = null;
 63 
 64             //如果有返回值,保存返回值到局部变量
 65             if (src_Method.ReturnType != typeof(void))
 66             {
 67                 result = il_ProxyMethod.DeclareLocal(src_Method.ReturnType);
 68                 il_ProxyMethod.Emit(OpCodes.Stloc, result);
 69 
 70                 //给AspectContext的属性Result赋值
 71                 var resultSetMethod = typeof(AspectContext).GetMethod("set_Result");
 72                 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
 73                 il_ProxyMethod.Emit(OpCodes.Ldloc, result);//加载返回值
 74                 il_ProxyMethod.Emit(OpCodes.Box, src_Method.ReturnType);
 75                 il_ProxyMethod.Emit(OpCodes.Call, resultSetMethod);//赋值
 76             }
 77 
 78             //调用横切对象的OnExit方法
 79             for (int i = 0; i < aspectCount; i++)
 80             {
 81                 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectLocalBuilders[i]);
 82                 il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
 83                 il_ProxyMethod.Emit(OpCodes.Callvirt, onExit_Methods[i]);
 84                 il_ProxyMethod.Emit(OpCodes.Nop);
 85             }
 86 
 87             il_ProxyMethod.BeginCatchBlock(typeof(Exception));//对应Catch
 88 
 89             //保存Exception到临时变量
 90             LocalBuilder exception = il_ProxyMethod.DeclareLocal(typeof(Exception));
 91 
 92             il_ProxyMethod.Emit(OpCodes.Stloc, exception);
 93 
 94             //复制Exception到Result
 95             il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
 96             il_ProxyMethod.Emit(OpCodes.Ldloc, exception);//错误信息
 97             il_ProxyMethod.Emit(OpCodes.Box, typeof(Exception));
 98             il_ProxyMethod.Emit(OpCodes.Call, typeof(AspectContext).GetMethod("set_Result"));//赋值
 99 
100             il_ProxyMethod.Emit(OpCodes.Ldloc,aspectExceptionAttribute);
101             il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
102             il_ProxyMethod.Emit(OpCodes.Callvirt, aspectExceptionType.GetMethod("OnEntry"));
103 
104             il_ProxyMethod.BeginFinallyBlock(); //对应Finally
105 
106             il_ProxyMethod.Emit(OpCodes.Ldloc, aspectExceptionAttribute);
107             il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
108             il_ProxyMethod.Emit(OpCodes.Callvirt, aspectExceptionType.GetMethod("OnExit"));
109 
111             il_ProxyMethod.EndExceptionBlock(); //异常处理结束
112 
113             //如果有返回值,则把返回值压栈
114             if (result != null)
115                 il_ProxyMethod.Emit(OpCodes.Ldloc, result);
116 
117             il_ProxyMethod.Emit(OpCodes.Ret);//返回
118         }

以  NYearLater 为例反编译后的代码如下:

 1     public override int NYearLater(int num)
 2     {
 3         AspectContext aspectContext = new AspectContext(this, "NYearLater", new object[]
 4         {
 5             num
 6         });
 7         AspectExceptionAttribute aspectExceptionAttribute = new AspectExceptionAttribute();
 8         int num2;
 9         try
10         {
11             LogAttribute logAttribute = new LogAttribute();
12             logAttribute.OnEntry(aspectContext);
13             num2 = base.NYearLater(num);
14             aspectContext.Result = num2;
15             logAttribute.OnExit(aspectContext);
16         }
17         catch (Exception ex)
18         {
19             aspectContext.Result = ex;
20             aspectExceptionAttribute.OnEntry(aspectContext);
21         }
22         finally
23         {
24             aspectExceptionAttribute.OnExit(aspectContext);
25         }
26         return num2;
27     }
  • 测试

 修改 NYearLater方法:如果大于200了抛出异常

 1         public virtual int NYearLater(int a)
 2         {
 3             int larter = Age + a;
 4 
 5             if (larter > 200)
 6             {
 7                 throw new Exception("Too Old!");
 8             }
 9 
10             return larter;
11         }

修改测试方法:

 1         public static void Test()
 2         {
 3             try
 4             {
 5                 AopTest WithPara = DynamicProxy.Create<AopTest>("lxl", 10); ;
 6 
 7                 WithPara.NYearLater(310);
 8 
 9                 Console.WriteLine("done...");
10 
11             }
12             catch (Exception ex)
13             {
14                 Console.WriteLine(ex.Message);
15             }
16         }

运行结果:

Log OnEntry:set_Name(lxl)
Log OnExit: set_Name

Finally  : set_Name
Log OnEntry:set_Age(10)
Log OnExit: set_Age

Finally  : set_Age
Log OnEntry:NYearLater(310) //以310调用方法
Log OnEntry:get_Age() 
Log OnExit: get_Age Result: 10

Finally  : get_Age

Exception : NYearLater Too Old! //捕获异常

Finally  : NYearLater 
done...

可以看到异常处理完成。

 

转载于:https://www.cnblogs.com/accode/p/10906431.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
纯手工打造Emit实现AOP private static void OverrideMethods(TypeBuilder tb, MethodInfo method) { if (!method.IsPublic|| !method.IsVirtual || IsObjectMethod(method)) return; Type[] paramTypes = GetParameterTypes(method); MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual; MethodBuilder mb = tb.DefineMethod(method.Name, attr, method.ReturnType, paramTypes); LocalBuilder result = null; ILGenerator il = mb.GetILGenerator(); bool is_void = method.ReturnType != typeof(void); if (is_void == false) result = il.DeclareLocal(method.ReturnType); object[] attrs = method.GetCustomAttributes(typeof(AspectAttribute), false); if (attrs != null) { //初始化所有当前方法用到的参数object[] CreateLocalParameterArr(il, paramTypes); //初始化AspectContext Type ctxType = typeof(AspectContext); ConstructorInfo info = ctxType.GetConstructor(Type.EmptyTypes); var ctx = il.DeclareLocal(ctxType); il.Emit(OpCodes.Newobj, info); il.Emit(OpCodes.Stloc, ctx); //给AspectContext的参数值属性ParameterArgs赋值 var propMethod = ctxType.GetMethod("set_ParameterArgs"); il.Emit(OpCodes.Ldloc, ctx); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Call, propMethod); int m = attrs.Length; LocalBuilder[] lbs = new LocalBuilder[m]; MethodInfo[] endInvokeMethods = new MethodInfo[m]; //初始化标记的横切对象,并调用横切对象的BeforeInvoke方法 for (int i = 0; i < m; i++) { var tmpType = attrs[i].GetType(); var aspect = il.DeclareLocal(tmpType); ConstructorInfo tmpInfo = tmpType.GetCon
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值