目 录
通过特性处理异常,也是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...
可以看到异常处理完成。