Aop动态生成代理类时支持带参数构造函数
2016-06-30 16:01
330 查看
一、背景
在某些情况下,我们需要植入AOP代码的类并没有默认构造函数。那么此时动态生成的代理类也需要相同签名的构造函数,并且内部调用原始类的构造函数。自己折腾了1晚上没搞定,现在搞定了发出来供大家一起学习探讨。
二、梳理功能点
在已支持通过默认构造函数进行AOP代码植入的情况下(以前发过一篇博文,传送门:大家一起Aop),实现该功能我们需要做的是:
1.如何通过获取原始类的构造函数参数列表,并使用Emit生成代理类的相应构造函数。
2.如何创建并保存实例化代理类的委托,加快实例化速度。
三、实现方案
功能1:
在原来的生成代理类,代理类中的方法处增加生成构造函数的代码。代码很简单,如下:
其中要注意2点,
①定义构造函数的时候需要指定MethodAttributes,平常我们代码编写的公有构造函数就是上面写的4个。
②因为我们定义的是构造函数,所以此处必须指定CallingConventions.HasThis。至于为什么去看msdn的解释,不在我们本次讨论范围内。
到这里我们的动态类的构造已经完成了,接下去解决功能2:
这里只要在原先直接取默认构造函数的地方增加一个判断,获取指定参数的构造函数来构造委托。下面贴代码:
这里需要的注意的点已经标红出来了。但这里仅是核心代码,在外层再封装几个重载用于生成不同的Func<>。
大功告成~,再进行一些简单的重构。测试效果:
四、收尾
源码附上:源码+Demo在此!
觉得有用记得点赞哦~
作者: Zachary_Fan
出处:http://www.cnblogs.com/Zachary-Fan/p/5629992.html
如果你想及时得到个人自写文章的消息推送,欢迎扫描下面的二维码~。
在某些情况下,我们需要植入AOP代码的类并没有默认构造函数。那么此时动态生成的代理类也需要相同签名的构造函数,并且内部调用原始类的构造函数。自己折腾了1晚上没搞定,现在搞定了发出来供大家一起学习探讨。
二、梳理功能点
在已支持通过默认构造函数进行AOP代码植入的情况下(以前发过一篇博文,传送门:大家一起Aop),实现该功能我们需要做的是:
1.如何通过获取原始类的构造函数参数列表,并使用Emit生成代理类的相应构造函数。
2.如何创建并保存实例化代理类的委托,加快实例化速度。
三、实现方案
功能1:
在原来的生成代理类,代理类中的方法处增加生成构造函数的代码。代码很简单,如下:
if (_parameters == null || _parameters.Length == 0) { return typeBuilder; } var baseConstructor = _originalType.GetConstructor(_parameterTypes); if (baseConstructor == null) throw new MissingMethodException("未找到相应参数的构造函数"); const MethodAttributes METHOD_ATTRIBUTES = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Public; var constructor = typeBuilder.DefineConstructor(METHOD_ATTRIBUTES, CallingConventions.HasThis, _parameterTypes); var il = constructor.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); for (int i = 1; i <= _parameters.Length; i++) //这里要注意下,索引为0的参数是当前对象本身 { il.Emit(OpCodes.Ldarg, i); } il.Emit(OpCodes.Call, baseConstructor); il.Emit(OpCodes.Ret); return typeBuilder;
其中要注意2点,
①定义构造函数的时候需要指定MethodAttributes,平常我们代码编写的公有构造函数就是上面写的4个。
②因为我们定义的是构造函数,所以此处必须指定CallingConventions.HasThis。至于为什么去看msdn的解释,不在我们本次讨论范围内。
到这里我们的动态类的构造已经完成了,接下去解决功能2:
这里只要在原先直接取默认构造函数的地方增加一个判断,获取指定参数的构造函数来构造委托。下面贴代码:
private DynamicMethod GetConstructorMethod<TReturnType>(Type aopType) { var method = _parameters == null || _parameters.Length == 0 ? new DynamicMethod("", typeof(TReturnType), null) : new DynamicMethod("", typeof(TReturnType), _parameterTypes); var il = method.GetILGenerator(); BuildConstructorIl(il, aopType); return method; } private void BuildConstructorIl(ILGenerator il, Type aopType) { if (_parameters == null || _parameters.Length == 0) { ConstructorInfo info = aopType.GetConstructor(Type.EmptyTypes); if (info == null) return; il.Emit(OpCodes.Newobj, info); il.Emit(OpCodes.Ret); } else { ConstructorInfo info = aopType.GetConstructor(_parameterTypes); if (info == null) return; var localInstance = il.DeclareLocal(aopType); for (int i = 0; i < _parameterTypes.Length; i++) //这里与上面的标红不同,这里因为是直接定义了一个方法,并且不存在实例,所以此处参数从索引0开始 il.Emit(OpCodes.Ldarg, i); il.Emit(OpCodes.Newobj, info); il.Emit(OpCodes.Stloc, localInstance); il.Emit(OpCodes.Ldloc, localInstance); il.Emit(OpCodes.Ret); } }
这里需要的注意的点已经标红出来了。但这里仅是核心代码,在外层再封装几个重载用于生成不同的Func<>。
public Func<TReturnType> CreateFunc<TReturnType>(Type aopType) { var method = GetConstructorMethod<TReturnType>(aopType); return method.CreateDelegate(typeof(Func<TReturnType>)) as Func<TReturnType>; } public Func<TP1, TReturnType> CreateFunc<TP1, TReturnType>(Type aopType) { var method = GetConstructorMethod<TReturnType>(aopType); return method.CreateDelegate(typeof(Func<TP1, TReturnType>)) as Func<TP1, TReturnType>; } public Func<TP1, TP2, TReturnType> CreateFunc<TP1, TP2, TReturnType>(Type aopType) { var method = GetConstructorMethod<TReturnType>(aopType); return method.CreateDelegate(typeof(Func<TP1, TP2, TReturnType>)) as Func<TP1, TP2, TReturnType>; }
大功告成~,再进行一些简单的重构。测试效果:
四、收尾
源码附上:源码+Demo在此!
觉得有用记得点赞哦~
作者: Zachary_Fan
出处:http://www.cnblogs.com/Zachary-Fan/p/5629992.html
如果你想及时得到个人自写文章的消息推送,欢迎扫描下面的二维码~。
相关文章推荐
- Linux性能评测工具之一:gprof篇
- shell基础之利用shell检测目录是否存在,不存在提示让用户创建目录
- linux下系统对于sigsegv错误时的处理
- 查看进程占用的内存情况
- OpenCV_(1):Mat结构的应用
- debian7系统设置固定IP
- 《Linux内核设计与实现》笔记——CPU的三种工作状态
- Linux nc命令详解
- linux命令 — lsof 查看进程打开那些文件 或者 查看文件给那个进程使用
- Nginx+Lua开发入门
- 温故之--Linux 初始化 init 系统
- Photoshop CS6破解
- 《Linux内核设计与实现》笔记——进程调度
- Hadoop2.7.1 集群部署及自动化脚本
- 虚拟化基础架构Windows 2008篇之10-使用WDS安装Windows 7
- Nginx的启动、停止、平滑重启
- opencv 界面画框
- linux Socket 中 setsockopt的SO_KEEPALIVE选项
- 虚拟化基础架构Windows 2008篇之9-配置Windows部署服务
- Debian配置JDK1.7 与Linux Java Helloworld