欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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类