博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 使用Emit实现动态AOP框架 进阶篇之异常处理
阅读量:4594 次
发布时间:2019-06-09

本文共 9671 字,大约阅读时间需要 32 分钟。

     目  录

通过特性处理异常,也是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             //存储到 aspectExceptionAttribute14             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到Result6  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(); //对应Finally105 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         try10         {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         finally23         {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
("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_NameFinally  : set_NameLog OnEntry:set_Age(10)Log OnExit: set_AgeFinally  : set_AgeLog OnEntry:NYearLater(310) //以310调用方法Log OnEntry:get_Age() Log OnExit: get_Age Result: 10Finally  : get_AgeException : NYearLater Too Old! //捕获异常Finally  : NYearLater done...

可以看到异常处理完成。

 

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

你可能感兴趣的文章
顺利通过EMC实验(14)
查看>>
usaco Cow Pedigrees
查看>>
php自带压缩类压缩文件夹
查看>>
【转】Install Win32 OpenSSH (test release)
查看>>
LA 4123 (计数 递推) Glenbow Museum
查看>>
SPOJ 375 树链剖分 QTREE - Query on a tree
查看>>
JavaScript对json对象数组排序(按照某个属性升降序排列)
查看>>
关于 注册页面浏览器自动添加账号密码问题?
查看>>
Python之装饰器
查看>>
04Array
查看>>
MeteoInfoLab脚本示例:计算不同区域平均值
查看>>
Spring -- 全注解下的IoC(1)
查看>>
C#中的值类型和引用类型的比较
查看>>
[NOI2018]屠龙勇士
查看>>
Python3.0科学计算学习之类
查看>>
关于web前端中遇到的html,css小知识点
查看>>
阿里云高级技术专家空见: CDN的数据化之路
查看>>
Container and injection
查看>>
【转】职场学做“功夫熊猫”
查看>>
OpenNMS架构介绍
查看>>