C# 使用Emit实现动态AOP框架 (三)
程序员文章站
2022-03-20 12:30:14
准备工作完成后,DynamicProxy类就可以开始了。 创建代理对象 Create 创建代理对象主要分为五步: (1)、获取被代理类型构造函数参数列表 1 /// 2 /// 创建代理类型 3 /// 4 ///
准备工作完成后,dynamicproxy类就可以开始了。
创建代理对象 create
创建代理对象主要分为五步:
(1)、获取被代理类型构造函数参数列表
type[] parametertypes = parameters == null ? type.emptytypes : parameters.select(p => p.gettype()).toarray();
(2)、根据构造函数参数列表创建代理类型
type proxytype = createproxytype(srctype, parametertypes);
(3)、使用动态方法生成创建代理类型实例的委托
createfunc<t>(proxytype, parametertypes)
(4)、生成proxytype对象,存入代理类型字典,以备二次调用
obj = new proxytype<t>(srctype.fullname, signature, createfunc<t>(proxytype, parametertypes)); func_dictionary.add(srctype.fullname + "(" + signature + ")", obj);
(5)、通过委托生成代理对象
func<object[], t> func = (obj as proxytype<t>).createfunc; if (func == null) throw new exception("unknown exception"); return func(parameters);
1 /// <summary> 2 /// 创建代理类型 3 /// </summary> 4 /// <param name="srctype">类型</param> 5 /// <param name="parametertypes">参数</param> 6 /// <returns></returns> 7 private static type createproxytype(type srctype, type[] parametertypes) 8 { 9 xnet.xcore.xdynamic.buildercollection bc = new xdynamic.buildercollection 10 (srctype.name + "_aop_assmely", srctype.name + "_aop_module", srctype.name + "_proxy", srctype, parametertypes); 11 12 13 foreach (var propertyinfo in srctype.getproperties()) 14 overrideproperty(bc.dynamictypebuilder, propertyinfo); 15 16 //切入方法 17 methodinfo[] methods = srctype.getmethods(bindingflags.public | bindingflags.instance); 18 19 for (int i = 0; i < methods.length; i++) 20 { 21 var method = methods[i]; 22 23 if (!method.ispublic || !method.isvirtual || xdynamic.isobjectmethod(method)) continue; 24 25 object[] aspectattributes = method.getcustomattributes(typeof(aspectattribute), false); 26 27 overridemethod(bc.dynamictypebuilder, method, aspectattributes); 28 } 29 30 type result = bc.dynamictypebuilder.createtype(); 31 32 bc.dynamicassemblybuilder.save(bc.assemblyname.name + ".dll"); 33 34 return result; 35 }
1.1、根据构造函数参数列表创建代理类型 createproxytype
(1)、通过emit生成动态程序集、动态模块以及动态类型
xnet.xcore.xdynamic.buildercollection bc = new xdynamic.buildercollection
(srctype.name + "_aop_assmely", srctype.name + "_aop_module", srctype.name + "_proxy", srctype, parametertypes);
(2)、重写被切入的属性
overrideproperty(bc.dynamictypebuilder, propertyinfo);
(3)、重写被切入的方法
overridemethod(bc.dynamictypebuilder, method, aspectattributes);
(4)、生成代理类型
type result = bc.dynamictypebuilder.createtype();
1 /// <summary> 2 /// 创建代理类型 3 /// </summary> 4 /// <param name="srctype">类型</param> 5 /// <param name="parametertypes">参数</param> 6 /// <returns></returns> 7 private static type createproxytype(type srctype, type[] parametertypes) 8 { 9 xnet.xcore.xdynamic.buildercollection bc = new xdynamic.buildercollection 10 (srctype.name + "_aop_assmely", srctype.name + "_aop_module", srctype.name + "_proxy", srctype, parametertypes); 11 12 13 foreach (var propertyinfo in srctype.getproperties()) 14 overrideproperty(bc.dynamictypebuilder, propertyinfo); 15 16 //切入方法 17 methodinfo[] methods = srctype.getmethods(bindingflags.public | bindingflags.instance); 18 19 for (int i = 0; i < methods.length; i++) 20 { 21 var method = methods[i]; 22 23 if (!method.ispublic || !method.isvirtual || xdynamic.isobjectmethod(method)) continue; 24 25 object[] aspectattributes = method.getcustomattributes(typeof(aspectattribute), false); 26 27 overridemethod(bc.dynamictypebuilder, method, aspectattributes); 28 } 29 30 type result = bc.dynamictypebuilder.createtype(); 31 32 bc.dynamicassemblybuilder.save(bc.assemblyname.name + ".dll"); 33 34 return result; 35 }
1.1.1 重写被切入的属性 overrideproperty
1 /// <summary> 2 /// 重写被代理类的属性 3 /// </summary> 4 /// <param name="dynamictypebuilder"></param> 5 /// <param name="info">属性信息</param> 6 /// <param name="rangetype">切面范围</param> 7 /// <param name="onentryexit">切面公共调用方法</param> 8 private static void overrideproperty(typebuilder dynamictypebuilder, propertyinfo info) 9 { 10 //不需要切入直接返回 11 object[] aspectattributes = info.getcustomattributes(typeof(aspectattribute), false); 12 13 if (aspectattributes.length == 0) return; 14 15 propertybuilder dynamicpropertybuilder = dynamictypebuilder.defineproperty(info.name, propertyattributes.hasdefault, info.propertytype, null); 16 17 //getter setter 方法标识 18 methodattributes getsetattr = methodattributes.public | methodattributes.specialname | methodattributes.hidebysig | methodattributes.virtual; 19 20 methodbuilder getter = dynamictypebuilder.definemethod("get_" + info.name, getsetattr, info.propertytype, type.emptytypes); 21 22 ilgenerator getil = getter.getilgenerator(); 23 24 ilgenerateproxymethod(getil, info.getgetmethod(), type.emptytypes, aspectattributes); 25 26 27 //覆盖自动生成的getter 28 methodinfo getmethod = info.getgetmethod(); 29 30 if (getmethod != null) dynamictypebuilder.definemethodoverride(getter, getmethod); 31 32 //给属性设置get、set方法 33 dynamicpropertybuilder.setgetmethod(getter); 34 35 36 //重写set 方法 37 methodbuilder setter = dynamictypebuilder.definemethod("set_" + info.name, getsetattr, typeof(void), new type[] { info.propertytype }); 38 39 ilgenerator setil = setter.getilgenerator(); 40 41 ilgenerateproxymethod(setil, info.getsetmethod(), new type[] { info.propertytype }, aspectattributes); 42 43 44 //覆盖自动生成的setter 45 methodinfo setmethod = info.getsetmethod(); 46 47 if (setmethod != null) dynamictypebuilder.definemethodoverride(setter, setmethod); 48 49 dynamicpropertybuilder.setsetmethod(setter); 50 }
1.1.2 重写被切入的方法 overridemethod
1 /// <summary> 2 /// 重写被代理类的指定方法 3 /// </summary> 4 /// <param name="typebuilder">类型</param> 5 /// <param name="src_method">被代理方法</param> 6 /// <param name="aspectattributes">代理特性集合</param> 7 private static void overridemethod(typebuilder typebuilder, methodinfo src_method, object[] aspectattributes) 8 { 9 if (aspectattributes == null || aspectattributes.length == 0) return; 10 11 methodattributes attr = methodattributes.public | methodattributes.family | methodattributes.hidebysig | methodattributes.virtual; 12 13 //获取当前方法参数列表 14 type[] paramtypes = xdynamic.getmethodparametertypes(src_method); 15 16 ilgenerator il = typebuilder.definemethod(src_method.name, attr, src_method.returntype, paramtypes).getilgenerator(); 17 18 ilgenerateproxymethod(il, src_method, paramtypes, aspectattributes); 19 }
1.1.3 生成代理方法 ilgenerateproxymethod
1 /// <summary> 2 /// 3 /// </summary> 4 /// <param name="il_proxymethod"></param> 5 /// <param name="src_method"></param> 6 /// <param name="paramtypes"></param> 7 /// <param name="aspectattributes"></param> 8 private static void ilgenerateproxymethod(ilgenerator il_proxymethod, methodinfo src_method, type[] paramtypes, object[] aspectattributes) 9 { 10 int aspectcount = aspectattributes.length; 11 12 //生成切面上下文 13 localbuilder aspectcontext = createaspectcontext(il_proxymethod, src_method.name, paramtypes); 14 15 //申明临时存放切面对象和onexit方法的变量 16 var aspectlocalbuilders = new localbuilder[aspectcount]; 17 var onexit_methods = new methodinfo[aspectcount]; 18 19 20 //初始化标记的切面对象,并调用切面对象的onentry方法 21 for (int i = 0; i < aspectcount; i++) 22 { 23 //创建一个切面对象 24 var aspecttype = aspectattributes[i].gettype(); 25 var aspect = il_proxymethod.declarelocal(aspecttype); 26 constructorinfo constructor = aspecttype.getconstructor(type.emptytypes); 27 28 il_proxymethod.emit(opcodes.newobj, constructor); 29 il_proxymethod.emit(opcodes.stloc, aspect); 30 31 var onentry_method = aspecttype.getmethod("onentry"); 32 onexit_methods[i] = aspecttype.getmethod("onexit"); 33 34 //调用beforeinvoke 35 il_proxymethod.emit(opcodes.ldloc, aspect); 36 il_proxymethod.emit(opcodes.ldloc, aspectcontext); 37 il_proxymethod.emit(opcodes.callvirt, onentry_method); 38 il_proxymethod.emit(opcodes.nop); 39 40 aspectlocalbuilders[i] = aspect; 41 } 42 43 //类对象,参数值依次入栈 44 for (int i = 0; i <= paramtypes.length; i++) 45 il_proxymethod.emit(opcodes.ldarg, i); 46 47 //调用基类的方法 48 il_proxymethod.emit(opcodes.call, src_method); 49 50 51 //定义返回值 52 localbuilder result = null; 53 54 //如果有返回值,保存返回值到局部变量 55 if (src_method.returntype != typeof(void)) 56 { 57 result = il_proxymethod.declarelocal(src_method.returntype); 58 il_proxymethod.emit(opcodes.stloc, result); 59 60 //给aspectcontext的属性result赋值 61 var resultsetmethod = typeof(aspectcontext).getmethod("set_result"); 62 il_proxymethod.emit(opcodes.ldloc, aspectcontext); //加载aspectcontext局部变量 63 il_proxymethod.emit(opcodes.ldloc, result);//加载返回值 64 il_proxymethod.emit(opcodes.box, src_method.returntype); 65 il_proxymethod.emit(opcodes.call, resultsetmethod);//赋值 66 } 67 68 //调用横切对象的onexit方法 69 for (int i = 0; i < aspectcount; i++) 70 { 71 il_proxymethod.emit(opcodes.ldloc, aspectlocalbuilders[i]); 72 il_proxymethod.emit(opcodes.ldloc, aspectcontext); 73 il_proxymethod.emit(opcodes.callvirt, onexit_methods[i]); 74 il_proxymethod.emit(opcodes.nop); 75 } 76 77 //如果有返回值,则把返回值压栈 78 if (result != null) 79 il_proxymethod.emit(opcodes.ldloc, result); 80 81 il_proxymethod.emit(opcodes.ret);//返回 82 }
1.1.4 生成切面上下文对象 createaspectcontext
1 /// <summary> 2 /// 生成切面上下文对象 3 /// </summary> 4 /// <param name="il"></param> 5 /// <param name="methodname">方法名称</param> 6 /// <param name="paramtypes">参数类型</param> 7 /// <returns></returns> 8 private static localbuilder createaspectcontext(ilgenerator il, string methodname, type[] paramtypes) 9 { 10 //aspectcontext.parameterargs 类型为 object[] 11 12 //声明一个类型为object的局部数组 13 il.declarelocal(typeof(object[])); 14 //数组长度入栈 15 il.emit(opcodes.ldc_i4, paramtypes.length); 16 //生成新数组 17 il.emit(opcodes.newarr, typeof(object)); 18 //赋值给局部数组变量 19 il.emit(opcodes.stloc_0); 20 21 //遍历参数,并存入数组 22 for (int i = 0; i < paramtypes.length; i++) 23 { 24 il.emit(opcodes.ldloc_0);//数组入栈 25 il.emit(opcodes.ldc_i4, i);//数组下标入栈 26 il.emit(opcodes.ldarg, i + 1);//按下标加载对应的参数 27 if (paramtypes[i].isvaluetype)//参数为值类型,装箱 28 il.emit(opcodes.box, paramtypes[i]); 29 il.emit(opcodes.stelem_ref);//将参数存入数组 30 } 31 32 //获取aspectcontext构造函数 33 type aspectcontexttype = typeof(aspectcontext); 34 constructorinfo info = aspectcontexttype.getconstructor(new type[] { typeof(object), typeof(string), typeof(object[]) }); 35 36 //生成一个aspectcontext 对象 37 il.emit(opcodes.ldarg_0);//加载调用对象 38 il.emit(opcodes.ldstr, methodname);//加载方法名称 39 il.emit(opcodes.ldloc_0);//加载由参数生成的局部数组变量 40 il.emit(opcodes.newobj, info); 41 42 //声明一个aspectcontext局部变量 43 localbuilder aspectcontext = il.declarelocal(aspectcontexttype); 44 il.emit(opcodes.stloc, aspectcontext); 45 46 return aspectcontext; 47 }
1.2 使用动态方法生成创建代理类型实例的委托
1 /// <summary> 2 /// 生成创建代理类型实例的委托 3 /// </summary> 4 /// <typeparam name="t">被代理类型</typeparam> 5 /// <param name="proxytype">代理类型</param> 6 /// <param name="parametertypes">代理类型构造函数参数类型</param> 7 /// <returns></returns> 8 private static func<object[], t> createfunc<t>(type proxytype, type[] parametertypes) 9 { 10 dynamicmethod method = new dynamicmethod(proxytype.name + "_cf", typeof(t), new type[] { typeof(object[]) }, true); 11 12 var il = method.getilgenerator(); 13 14 //根据t类型的构造函数参数列表,依次将 object[] parameters 中对应的值加载到堆栈(并做相应类型转换),以被t类型的构造函数使用 15 for (int i = 0; i < parametertypes.length; i++) 16 { 17 18 il.emit(opcodes.ldarg_0); 19 il.emit(opcodes.ldc_i4, i); 20 il.emit(opcodes.ldelem_ref); 21 22 if (parametertypes[i].isvaluetype) 23 // 如果是值类型,拆箱 24 il.emit(opcodes.unbox_any, parametertypes[i]); 25 else 26 // 如果是引用类型,转换 27 il.emit(opcodes.castclass, parametertypes[i]); 28 } 29 30 constructorinfo info = proxytype.getconstructor(parametertypes); 31 32 if (info == null) throw new exception("代理类不存在,与指定参数列表相对应的构造函数。"); 33 34 il.emit(opcodes.newobj, info); 35 il.emit(opcodes.ret); 36 37 //建立《生成指定类型t的实例》的委托 38 return method.createdelegate(typeof(func<object[], t>)) as func<object[], t>; 39 }
1.3 proxytype类
1 public class proxytype<t> 2 { 3 #region 构造函数 4 /// <summary> 5 /// 构造函数 6 /// </summary> 7 /// <param name="name">类型名称</param> 8 /// <param name="parametersignature">构造函数参数签名</param> 9 /// <param name="createfunc">创建被代理类型实例的委托</param> 10 public proxytype(string name, string parametersignature, func<object[], t> createfunc) 11 { 12 name = name; parametersignature = parametersignature; createfunc = createfunc; 13 } 14 #endregion 15 16 #region 属性 17 18 /// <summary> 19 /// 名称 20 /// </summary> 21 public string name { get; set; } 22 23 /// <summary> 24 /// 参数类型签名 25 /// </summary> 26 public string parametersignature { get; set; } 27 28 /// <summary> 29 /// 创建被代理类型实例的委托 30 /// </summary> 31 public func<object[], t> createfunc { get; set; } 32 33 #endregion 34 }
到此为止一个简单的aop框架就完成了。下一篇会介绍一个下buildercollection类
下一篇: 免费解压啤酒