aop框架:轻量级AOP框架-移植python的装饰器(Decorator)到C#(编码篇)

  . 前言

  在轻量级AOP框架-移植python装饰器(Decorator)到C#(研究篇)文章分析了Python中Decorator原理以及C#移植可行性在本篇中文章将继续探讨如何将这个想法实实在在表现出来因此本篇目标是:个初级但是可用Decorator实现

  如果您对本文基本思路存在疑惑请先阅读研究篇

   2. 实现分析

  上篇中我们考虑实现个Wrapper类来做到模仿Python替换功能然而在实际使用中如果靠人工书写很显然是个不切实际想法因此框架关键在于对被装饰思路方法处理当前我们般使用动态代理或者静态织入方式进行该操作然而无论是哪种思路方法关键点都在于对现有代码“动态修改”(动态代理修改在于运行时静态织入修改在于编译时)

  在本篇中我们考虑个动态代理实现具体运作方式如下:

  1. 运行时采用框架中工厂生成代理对象即:框架中工厂思路方法传入欲生成对象类型因此对象创建方式将发生改变:默认情况下我们可能采用 var testClass = TestClass;方式生成对象在使用代理情况下必须强制使用var testClass = xxx.CreateInstanse<TestClass>;方式生成对象

  2. 框架工厂类获取到对象类型的后检查对象是否为可继承对象如果不是则无法生成代理类否则进行下

  3. 动态类生产引擎生成TestClassWrapper类,并从TestClass继承

  4. 采用方式重写TestClass中欲进行处理思路方法以满足上篇中预设结果

  5. 生成TestClassWrapper类例子并返回

   3. 编码难点

  在了解了具体运作方式的后我们可以分别考虑各个步骤实现难点和第 2都不难使用基本反射即可实现主要问题在于3-5步下面我们分别对这几步实现进行编码难点分析

  对于第 3步类继承很显然这首先要具备个条件那就是原始类是可继承否则也无从谈起TestClassWrapper生成如果满足条件那么可以使用反射创建动态类同时在c#中我们需要创建个动态集来容纳这些动态类

  对于第 4步系统需要重写欲处理思路方法要达到这个目标我们只能请出我们终极大神MSIL了在C#中可以使用Emit方式进行IL嵌入编程虽然麻烦了点但这总算也能高效解决问题

  对于第 5步般来说可以Activator.CreateInstance思路方法来创建对象然而在本人篇博客探究.net对象创建, 质疑再谈Activator.CreateInstance(Type type)思路方法创建对象和Expression Tree创建对象性能比较我们可以了解到Activator.CreateInstance并不是最高效做法因此框架将考虑使用更高效方式如Emit或者ExpressionTree方式生成委托并构造对象

   4. 具体编码

  在编码前为了方便快速构造框架个人将些成熟代码放入框架中以提高效率这部分代码主要有:FastReflection可以通过Emit快速构造思路方法委托CodeGeneratorNbear框架中个IL编程帮助类通过它可以让我们简化不少IL操作

  现在万事俱备我们开始步步创造框架吧首先定义DecoratorFilter接口以方便扩展Attribute同时为了方便我们也定义个DecoratorContexe来取代上篇中直接传入Wrapper思路方法委托对象DecoratorFilter接口定义如下:

01     public erface IDecoratorFilter {
02         Func<object, object, object> Execute(DecoratorContext context);
03 }
04     其中DecoratorContext类包含了欲封装思路方法基本属性其定义如下:
05     public sealed  DecoratorContext {
06         /// <summary>
07         /// 该思路方法通用委托
08         /// </summary>
09         public Func<object, object, object> Invoker { get; private ; }
10  
11         /// <summary>
12         /// this对象
13         /// </summary>
14         public object Instanse { get; private ; }
15  
16         /// <summary>
17         /// 思路方法参数列表
18         /// </summary>
19         public object Parameters { get; private ; }
20  
21         public DecoratorContext(Func<object, object, object> invoker, object instanse, object parameters) {
22             Invoker = invoker;
23             Instanse = instanse;
24             Parameters = parameters;
25         }
26     }


  然后需要完成是DynamicTypeBuilder类该类负责动态动态类型动态思路方法创建具体实现如下:

01     ernal  DynamicTypeBuilder {
02         //为动态集生成名称
03         private readonly  assemblyName = Guid.NewGuid.;
04         //集主模块
05         private readonly  ModuleName = "Main";
06  
07         public AssemblyBuilder AssemblyBuilder { get; private ; }
08  
09         public ModuleBuilder MainModuleBuilder { get; private ; }
10  
11         public DynamicTypeBuilder {
12             AssemblyName an =  AssemblyName(assemblyName);
13             //构造个可运行动态集对象
14             AssemblyBuilder = AppDo.CurrentDo.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
15             //为该集构造主模块
16             MainModuleBuilder = AssemblyBuilder.DefineDynamicModule(ModuleName);
17         }
18  
19         /// <summary>
20         /// 从Type类派生个新代理类
21         /// </summary>
22         /// <param name="type">基类</param>
23         /// <s></s>
24         public TypeBuilder CreateTypeBuilder(Type type) {
25             TypeBuilder typeBuilder = MainModuleBuilder.DefineType(type.Name + "_" + Guid.NewGuid.,
26                 TypeAttributes.Class | TypeAttributes.Public,
27                 type);
28              typeBuilder;
29         }
30  
31         /// <summary>
32         /// 根据给定思路方法对象和类型对象构造CodeGenerator
33         /// </summary>
34         /// <param name="typeBuilder"></param>
35         /// <param name="method"></param>
36         /// <s></s>
37         public CodeGenerator CreateMethodCodeGenerator(TypeBuilder typeBuilder, MethodInfo method) {
38             CodeGenerator cg =  CodeGenerator(typeBuilder,
39                 method.Name,
40                 MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.HideBySig,
41                 CallingConventions.HasThis,
42                 method.ReturnType,
43                 method.GetParameters.Select(e => e.ParameterType).ToArray);
44             typeBuilder.DefineMethodOverride(cg.CurrentMethod, method);
45              cg;
46         }
47 }


  为了提高框架运行效率系统也构造个简单缓存Cache系统将缓存Cache些元数据详细情况可以参考完整源文件

  最后考虑最麻烦TypeFactory类该类中最重要思路方法就是CreateType它可以使说框架中最核心部分了通过该该思路方法我们创建了个新Class该Class中完成了Decorator核心实现下面给出该思路方法实现该类完整实现也请参考源码

001 public  Type CreateType(Type rawType) {
002     var typeBuilder = builder.CreateTypeBuilder(rawType);
003     MetaCacheItem metaCacheItem = MetaCache.Get(rawType);
004     MethodInfo getTypeMethodInfo = rawType.GetMethod("GetType");
005     foreach (var item in metaCacheItem.Methods) {
006          (item.Method.IsVirtual && item.Filters != null && item.Filters.Length > 0) {
007             var cg = builder.CreateMethodCodeGenerator(typeBuilder, item.Method);
008             var parameters = item.Method.GetParameters;
009             var cmpLabel = cg.DefineLabel;
010             var loopLabel = cg.DefineLabel;
011             //Type type;
012             var typeLocal = cg.DeclareLocal(typeType);
013             //MethodInfo thisMethodInfo;
014             var thisMethodInfoLocal = cg.DeclareLocal(methodInfoType);
015             //Type typeParameters;
016             var typeParametersLocal = cg.DeclareLocal(typeArrayType);
017             //MetaCacheItem metaCacheItem;
018             var metaCacheItemLocal = cg.DeclareLocal(metaCacheItemType);
019             //MetaMethodInfo metaMethodInfo;
020             var metaMethodInfoLocal = cg.DeclareLocal(metaMethodInfoType);
021             //Func<object, object, object> fun;
022             var funLocal = cg.DeclareLocal(genericInvokerType);
023             //object parameters;
024             var parametersLocal = cg.DeclareLocal(objectArrayType);
025             //IDecoratorFilter filters;
026             var filtersLocal = cg.DeclareLocal(iDecoratorFilterArrayType);
027             //IDecoratorFilter item;
028             var itemLocal = cg.DeclareLocal(iDecoratorFilterType);
029             // num;
030             var numLocal = cg.DeclareLocal(32Type);
031             //type = this.GetType;
032             //cg.Ldarg(0);
033             //cg.Call(getTypeMethodInfo);
034             cg.Ldtoken(rawType);
035             cg.Call(getTypeFromHandleMethodInfo);
036             cg.Stloc(typeLocal);
037             //typeParameters =  Type { xxx };
038             cg.NewArray(typeType, parameters.Length);
039             cg.Stloc(typeParametersLocal);
040             for ( i = 0; i < parameters.Length; i) {
041                 cg.Ldloc(typeParametersLocal);
042                 cg.Ldc(i);
043                 cg.Ldtoken(parameters[i].ParameterType);
044                 cg.Call(getTypeFromHandleMethodInfo);
045                 //cg.Ldarg(i + 1);
046                 //cg.Call(getTypeMethodInfo);
047                 cg.Stelem(typeType);
048             }
049             //thisMethodInfo = type.GetMethod("xxx", typeParameters);
050             cg.Ldloc(typeLocal);
051             cg.Ldstr(item.Method.Name);
052             cg.Ldloc(typeParametersLocal);
053             cg.Call(getMethodMethodInfo);
054             cg.Stloc(thisMethodInfoLocal);
055             //metaCacheItem = MetaCache.Get(type);
056             cg.Ldloc(typeLocal);
057             cg.Call(metaCacheGetMethodInfo);
058             cg.Stloc(metaCacheItemLocal);
059             //metaMethodInfo = TypeFactory.FindMetaMethodInfo(metaCacheItem.Methods, thisMethod);
060             cg.Ldloc(metaCacheItemLocal);
061             cg.Call(metaCacheItemMethodsGetMethodInfo);
062             cg.Ldloc(thisMethodInfoLocal);
063             cg.Call(findMetaMethodInfoMethodInfo);
064             cg.Stloc(metaMethodInfoLocal);
065             //fun = TypeFactory.CreateGenericInvoker(metaMethodInfo.Method);
066             cg.Ldloc(metaMethodInfoLocal);
067             cg.Call(metaMethodInfoMethodGetMethodInfo);
068             cg.Call(createGenericInvokerMethodInfo);
069             cg.Stloc(funLocal);
070             //parameters =  object { xxx };
071             cg.NewArray(objectType, parameters.Length);
072             cg.Stloc(parametersLocal);
073             for ( i = 0; i < parameters.Length; i) {
074                 cg.Ldloc(parametersLocal);
075                 cg.Ldc(i);
076                 cg.Ldarg(i + 1);
077                  (parameters[i].ParameterType.IsValueType) {
078                     cg.Box(parameters[i].ParameterType);
079                 }
080                 cg.Stelem(typeType);
081             }
082             cg.Ldloc(metaMethodInfoLocal);
083             cg.Call(metaMethodInfoFiltersGetMethodInfo);
084             cg.Stloc(filtersLocal);
085             //开始循环
086             cg.Ldc(0);
087             cg.Stloc(numLocal);
088             cg.Br(cmpLabel);
089             cg.MarkLabel(loopLabel);
090             cg.Ldloc(filtersLocal);
091             cg.Ldloc(numLocal);
092             cg.Ldelem(iDecoratorFilterType);
093             cg.Stloc(itemLocal);
094             //loop
095             //item.Execute( DecoratorContext(fun, this, parameters));
096             cg.Ldloc(itemLocal);
097             cg.Ldloc(funLocal);
098             cg.Ldarg(0);
099             cg.Ldloc(parametersLocal);
100             cg.New(decoratorContextConstructorInfo);
101             cg.Call(iDecoratorFilterExecuteMethodInfo);
102             cg.Stloc(funLocal);
103             //endloop
104             cg.Ldloc(numLocal);
105             cg.Ldc(1);
106             cg.Add;
107             cg.Stloc(numLocal);
108             cg.MarkLabel(cmpLabel);
109             cg.Ldloc(numLocal);
110             cg.Ldloc(filtersLocal);
111             cg.Ldlen;
112             cg.Blt(loopLabel);
113             // ()fun(this, parameters)
114             cg.Ldloc(funLocal);
115             cg.Ldarg(0);
116             cg.Ldloc(parametersLocal);
117             cg.Call(genericInvokeInvokerMethodInfo);
118              (item.Method.ReturnType != voidType && item.Method.ReturnType != objectType) {
119                 cg.ConvertValue(objectType, item.Method.ReturnType);
120             }   (item.Method.ReturnType  voidType) {
121                 cg.Pop;
122             }
123             cg.Ret;
124         }
125     }
126      typeBuilder.CreateType;
127 }


  将这部分IL翻译下,如果我们定义了个思路方法public virtual Test( p)那么自动生成思路方法大致会像下面

01 public override  Test( p) {
02     Type type = typeof(TestClass);
03     MethodInfo thisMethod = type.GetMethod("Test",  Type { typeof() });
04     MetaCacheItem metaCacheItem = MetaCache.Get(type);
05     MetaMethodInfo thisMetaMethod = metaCacheItem.Methods.FirstOrDefault(e => e.Method  thisMethod);
06     Func<object, object, object> fun = TypeFactory.CreateGenericInvoker(thisMetaMethod.Method);
07     object parameters =  object { p };
08     foreach (var item in thisMetaMethod.Filters) {
09         DecoratorContext context =  DecoratorContext(fun, this, parameters);
10         fun = item.Execute(context);
11     }
12      ()fun(this, parameters);
13 }


   5. 框架测试

  首先测试功能我们仍然以上篇中第个Python代码为例想办法达到效果准备代码如下:

01     /// <summary>
02     /// 和@logger功能LoggerAttribute实现
03     /// </summary>
04     public  LoggerAttribute : Attribute, IDecoratorFilter {
05         public  Name { get; private ; }
06  
07         public LoggerAttribute( name) {
08             Name = name;
09         }
10  
11         #region IDecoratorFilter Members
12  
13         public Func<object, object, object> Execute(DecoratorContext context) {
14              (instanse, parameters) => {
15                 Console.WriteLine("User is {0}.", Name);
16                 Console.WriteLine("Start Logging.");
17                 var result = context.Invoker(instanse, parameters);
18                 Console.WriteLine("End Logging.");
19                  result;
20             };
21         }
22  
23         #endregion
24 }
25  
26     /// <summary>
27     /// 和@debuger功能DebuggerAttribute实现
28     /// </summary>
29     public  DebuggerAttribute : Attribute, IDecoratorFilter {
30         public  Name { get; private ; }
31  
32         public DebuggerAttribute( name) {
33             Name = name;
34         }
35  
36         #region IDecoratorFilter Members
37  
38         public Func<object, object, object> Execute(DecoratorContext context) {
39              (instanse, parameters) => {
40                 Console.WriteLine("Debug {0}", Name);
41                 Console.WriteLine("Start Debug.");
42                 var result = context.Invoker(instanse, parameters);
43                 Console.WriteLine("End Debug.");
44                  result;
45             };
46         }
47  
48         #endregion
49 }
50  
51     public  TestClass {
52         [Logger("Leven")]
53         [Debugger("test")]
54         public virtual  Test {
55             Console.WriteLine("Method TestClass::Test called.");
56              "I am Result.";
57         }
58 }


  测试代码很简单:

1 var instanse = TypeFactory.CreateInstanse<TestClass>;
2 Console.WriteLine(instanse.Test);


  运行结果如下图所示:



  执行得到和Python代码完全结果至此框架功能实现完毕

  接下来用CodeTimer对框架性能做个简单测试,分别对比无代理思路方法,动态代理思路方法,手动继承思路方法执行效率进行测试,测试代码如下:

01 var instanse = TypeFactory.CreateInstanse<TestClass>;
02 TestClass rawInstanse =  TestClass;
03 TestClassStatic Instanse =  TestClassStatic;
04  
05 //first call
06 rawInstanse.Test2;
07 instanse.Test2;
08 Instanse.Test2;
09  
10 CodeTimer.Initialize;
11  num = 10000;
12 CodeTimer.Time("Raw Type", num,  => {
13     rawInstanse.Test2;
14 });
15 CodeTimer.Time("Proxy Type", num,  => {
16     instanse.Test2;
17 });
18 CodeTimer.Time("Static Type", num,  => {
19     Instanse.Test2;
20 });






  看到结果很是让人始料不及,代理思路方法和手写思路方法执行速度致倒是在预料的中,毕竟IL是完全,但是有Decorator和无Decorator效率差距实在无法让人接受很显然我们代理思路方法实现效率上无法过关因此本框架虽然功能上已经达到要求但是性能上还有很大优化空间

   6. 本篇小结

  在本篇中我们完成了框架基本设计让框架成功实现了我们功能目标但是通过测试表明框架性能还远不能达到我们要求因此在下篇中(暂定名:优化篇)我们将详细分析框架性能瓶颈并进行优化使得本框架达到简单高效结果



  本文举例源代码或素材下载

Tags:  什么是轻量级框架 轻量级框架 .netaop框架 aop框架

延伸阅读

最新评论

发表评论