目  录

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

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

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

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

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

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

  • 定义异常处理特性AspectExceptionAttribute

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

  public class AspectExceptionAttribute : AspectAttribute
{
public override InterceptType InterceptType { get; set; } public override void OnEntry(AspectContext context)
{
if (context != null)
{
if (context.Result != null && context.Result is Exception)
{
Console.WriteLine("Exception : " + context.Name + " " + (context.Result as Exception).Message);
}
} } public override void OnExit(AspectContext context)
{
if (context != null)
{
Console.WriteLine("Finally : " + context.Name);
}
}
  • 在ILGenerateProxyMethod方法中加入异常处理代码

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

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

             //获取异常处理类型
var aspectExceptionType = typeof(AspectExceptionAttribute); //申明一个异常处理特性对象
var aspectExceptionAttribute = il_ProxyMethod.DeclareLocal(aspectExceptionType); //获取其构造函数
ConstructorInfo temp = aspectExceptionType.GetConstructor(Type.EmptyTypes); //生成一个新对象
il_ProxyMethod.Emit(OpCodes.Newobj, temp); //存储到 aspectExceptionAttribute
il_ProxyMethod.Emit(OpCodes.Stloc, aspectExceptionAttribute);

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

 //加载异常特性对象                
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代码如下:

  LocalBuilder exception = il_ProxyMethod.DeclareLocal(typeof(Exception));

  il_ProxyMethod.Emit(OpCodes.Stloc, exception);

  //复制Exception到Result
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
il_ProxyMethod.Emit(OpCodes.Ldloc, exception);//错误信息
il_ProxyMethod.Emit(OpCodes.Box, typeof(Exception));
il_ProxyMethod.Emit(OpCodes.Call, typeof(AspectContext).GetMethod("set_Result"));//赋值

完整的ILGenerateProxyMethod的方法如下:

       private static void ILGenerateProxyMethod(ILGenerator il_ProxyMethod, MethodInfo src_Method, Type[] paramTypes, object[] aspectAttributes)
{
int aspectCount = aspectAttributes.Length; //生成切面上下文
LocalBuilder aspectContext = CreateAspectContext(il_ProxyMethod, src_Method.Name, paramTypes); //申明临时存放切面对象和OnExit方法的变量
var aspectLocalBuilders = new LocalBuilder[aspectCount];
var onExit_Methods = new MethodInfo[aspectCount]; //获取异常处理类型
var aspectExceptionType = typeof(AspectExceptionAttribute); //申明一个异常处理特性对象
var aspectExceptionAttribute = il_ProxyMethod.DeclareLocal(aspectExceptionType); //获取其构造函数
ConstructorInfo temp = aspectExceptionType.GetConstructor(Type.EmptyTypes); //生成一个新对象
il_ProxyMethod.Emit(OpCodes.Newobj, temp); //存储到 aspectExceptionAttribute
il_ProxyMethod.Emit(OpCodes.Stloc, aspectExceptionAttribute); Label tryLabel = il_ProxyMethod.BeginExceptionBlock();//对应Try //初始化标记的切面对象,并调用切面对象的OnEntry方法
for (int i = ; i < aspectCount; i++)
{
//创建一个切面对象
var aspectType = aspectAttributes[i].GetType();
var aspect = il_ProxyMethod.DeclareLocal(aspectType);
ConstructorInfo constructor = aspectType.GetConstructor(Type.EmptyTypes); il_ProxyMethod.Emit(OpCodes.Newobj, constructor);
il_ProxyMethod.Emit(OpCodes.Stloc, aspect); var onEntry_method = aspectType.GetMethod("OnEntry");
onExit_Methods[i] = aspectType.GetMethod("OnExit"); //调用OnEntry
il_ProxyMethod.Emit(OpCodes.Ldloc, aspect);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, onEntry_method);
il_ProxyMethod.Emit(OpCodes.Nop); aspectLocalBuilders[i] = aspect;
} //类对象,参数值依次入栈
for (int i = ; i <= paramTypes.Length; i++)
il_ProxyMethod.Emit(OpCodes.Ldarg, i); //调用基类的方法
il_ProxyMethod.Emit(OpCodes.Call, src_Method); //定义返回值
LocalBuilder result = null; //如果有返回值,保存返回值到局部变量
if (src_Method.ReturnType != typeof(void))
{
result = il_ProxyMethod.DeclareLocal(src_Method.ReturnType);
il_ProxyMethod.Emit(OpCodes.Stloc, result); //给AspectContext的属性Result赋值
var resultSetMethod = typeof(AspectContext).GetMethod("set_Result");
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
il_ProxyMethod.Emit(OpCodes.Ldloc, result);//加载返回值
il_ProxyMethod.Emit(OpCodes.Box, src_Method.ReturnType);
il_ProxyMethod.Emit(OpCodes.Call, resultSetMethod);//赋值
} //调用横切对象的OnExit方法
for (int i = ; i < aspectCount; i++)
{
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectLocalBuilders[i]);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, onExit_Methods[i]);
il_ProxyMethod.Emit(OpCodes.Nop);
} il_ProxyMethod.BeginCatchBlock(typeof(Exception));//对应Catch //保存Exception到临时变量
LocalBuilder exception = il_ProxyMethod.DeclareLocal(typeof(Exception)); il_ProxyMethod.Emit(OpCodes.Stloc, exception); //复制Exception到Result
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
il_ProxyMethod.Emit(OpCodes.Ldloc, exception);//错误信息
il_ProxyMethod.Emit(OpCodes.Box, typeof(Exception));
il_ProxyMethod.Emit(OpCodes.Call, typeof(AspectContext).GetMethod("set_Result"));//赋值 il_ProxyMethod.Emit(OpCodes.Ldloc,aspectExceptionAttribute);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, aspectExceptionType.GetMethod("OnEntry")); il_ProxyMethod.BeginFinallyBlock(); //对应Finally il_ProxyMethod.Emit(OpCodes.Ldloc, aspectExceptionAttribute);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, aspectExceptionType.GetMethod("OnExit")); il_ProxyMethod.EndExceptionBlock(); //异常处理结束 //如果有返回值,则把返回值压栈
if (result != null)
il_ProxyMethod.Emit(OpCodes.Ldloc, result); il_ProxyMethod.Emit(OpCodes.Ret);//返回
}

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

     public override int NYearLater(int num)
{
AspectContext aspectContext = new AspectContext(this, "NYearLater", new object[]
{
num
});
AspectExceptionAttribute aspectExceptionAttribute = new AspectExceptionAttribute();
int num2;
try
{
LogAttribute logAttribute = new LogAttribute();
logAttribute.OnEntry(aspectContext);
num2 = base.NYearLater(num);
aspectContext.Result = num2;
logAttribute.OnExit(aspectContext);
}
catch (Exception ex)
{
aspectContext.Result = ex;
aspectExceptionAttribute.OnEntry(aspectContext);
}
finally
{
aspectExceptionAttribute.OnExit(aspectContext);
}
return num2;
}
  • 测试

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

         public virtual int NYearLater(int a)
{
int larter = Age + a; if (larter > )
{
throw new Exception("Too Old!");
} return larter;
}

修改测试方法:

         public static void Test()
{
try
{
AopTest WithPara = DynamicProxy.Create<AopTest>("lxl", ); ; WithPara.NYearLater(); Console.WriteLine("done..."); }
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

运行结果:

Log OnEntry:set_Name(lxl)
Log OnExit: set_Name Finally : set_Name
Log OnEntry:set_Age()
Log OnExit: set_Age Finally : set_Age
Log OnEntry:NYearLater() //以310调用方法
Log OnEntry:get_Age()
Log OnExit: get_Age Result: Finally : get_Age Exception : NYearLater Too Old! //捕获异常 Finally : NYearLater
done...

可以看到异常处理完成。

C# 使用Emit实现动态AOP框架 进阶篇之异常处理的更多相关文章

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

    目  录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...

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

    目  录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...

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

    目  录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...

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

    目  录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...

  5. hadoop之yarn详解(框架进阶篇)

    前面在hadoop之yarn详解(基础架构篇)这篇文章提到了yarn的重要组件有ResourceManager,NodeManager,ApplicationMaster等,以及yarn调度作业的运行 ...

  6. 【Spring AOP】Spring AOP之如何通过注解的方式实现各种通知类型的AOP操作进阶篇(3)

    一.切入点表达式的各种类型 切入点表达式的作用:限制连接点的匹配(满足时对应的aspect方法会被执行) 1)execution:用于匹配方法执行连接点.Spring AOP用户可能最经常使用exec ...

  7. C#利用Emit反射实现AOP,以及平台化框架封装思路

    C#利用Emit反射实现AOP,以及平台化框架封装思路 这是前两天扒的一段动态代理AOP代码,用的Emit反射生成子类来实现代理模式,在这里做个小笔记,然后讨论一下AOP框架的实现思路. 首先是主函数 ...

  8. .NET 下基于动态代理的 AOP 框架实现揭秘

    .NET 下基于动态代理的 AOP 框架实现揭秘 Intro 之前基于 Roslyn 实现了一个简单的条件解析引擎,想了解的可以看这篇文章 https://www.cnblogs.com/weihan ...

  9. Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架

    类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...

随机推荐

  1. Netfilter 之 钩子函数与钩子点关系图

    概述 通过钩子点和优先级的代码追溯,得到如下对应关系图,图中横坐标为钩子点,纵坐标为优先级,每个钩子点上的钩子函数按照优先级排布: 详细分析 5个钩子点如下所示,在这个五个钩子点上的钩子函数按照上面的 ...

  2. Nginx数据结构之内存池

    基本结构 1. ngx_pool_t struct ngx_pool_s { ngx_pool_data_t d; size_t max; ngx_pool_t *current; ngx_chain ...

  3. 【软件工程】Beta版本演示

    团队信息 队名:女生都队 组长博客: 博客链接 成员 学号 史恩泽(组长) 031702122 施金海 031702121 阮君曦 031702116 陈银山 031702137 李季城 031702 ...

  4. Ubuntu 配置ISCSI服务

    摘要:sudo apt-get install iscsitarget立刻搞定, 然后编辑配置文件:sudovim/etc/ietd.conf默认的配置文件, 有详细的配置说明和示例,本博先备份了事, ...

  5. Qt那点事儿(三) 论父对象与子对象的关系

    第三回 父与子 70后的道友都应该看过这么一部片子叫做<<父子情深>>.讲述的是一个小男孩患了绝症,父亲为了满足他的愿望,让已关门的游乐园为他们父子俩重新开放.在游乐园尽情地玩 ...

  6. 信息学竞赛一本通提高版AC题解—例题1.1活动安排

    书中代码有误.书中为sort(a+1,a+n+1,Cmp). // // Created by yuxi on 19-1-13. // /* * * <信息学竞赛一本通-提高版>全部AC解 ...

  7. react+laravel与服务端渲染的几点思考

    一.前后端完全分离 1.用React.js做MVC中的V,剩下的交给Laravel 2.Laravel用来做API接口开发. 3.好处:实现了前后端开发的分离,从而加快前后端开发效率.另外若是多端的如 ...

  8. Jmeter性能测试工具的使用(Web性能测试)

    Jmeter性能测试工具的使用(Web性能测试) 1.下载 http://pan.baidu.com/s/1o7p18Ye 该软件不用安装,直接解压打开即可使用. 2.使用 这里就在win下进行,图形 ...

  9. [Spark News] Spark + GPU are the next generation technology

    一.资源:Spark进行机器学习,支持GPU From:https://my.oschina.net/u/2306127/blog/1602291 为了使用Spark进行机器学习,支持GPU是必须的, ...

  10. 搭建Kubernetes容器集群管理系统

    1.Kubernetes 概述 Kubernetes 是 Google 开源的容器集群管理系统,基于 Docker 构建一个容器的调度服务,提供资源调度.均衡容灾.服务注册.劢态扩缩容等功能套件. 基 ...