赞助商
一. 前言

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

    如果您对本文的基本思路存在疑惑,请先阅读思考篇。

二. 实现分析

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

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

  1. 运行时采用框架中的工厂生成代理对象,即:调用框架中的工厂方法,传入欲生成对象类型。因此对象创建方式将发生改变:默认情况下,我们可能采用 var testClass = new TestClass();的方式生成对象,在使用代理的情况下,必须强制使用var testClass = xxx.CreateInstanse<TestClass>();的方式生成对象。
  2. 框架工厂类获取到对象类型之后,检查对象是否为可继承对象,如果不是,则无法生成代理类,否则,进行下一步。
  3. 调用动态类生产引擎,生成TestClassWrapper类,并从TestClass继承。
  4. 采用一定的方式,重写TestClass中欲进行处理的方法,以满足上一篇中预设的结果
  5. 生成TestClassWrapper类实例并返回

三. 编码难点


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

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

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

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

四. 具体编码


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

    现在万事俱备,我们开始一步步的创造框架吧,首先定义DecoratorFilter接口,以方便扩展Attribute,同时,为了方便,我们也定义一个DecoratorContexe来取代上篇中的直接传入Wrapper方法的委托对象,DecoratorFilter接口定义如下:
  1. 01            public interface IDecoratorFilter {
  2. 02                Func<object, object[], object> Execute(DecoratorContext context);
  3. 03        }
  4. 04            其中的DecoratorContext类包含了欲封装方法的基本属性,其定义如下:
  5. 05            public sealed class DecoratorContext {
  6. 06                /// <summary>
  7. 07                /// 该方法通用调用委托
  8. 08                /// </summary>
  9. 09                public Func<object, object[], object> Invoker { get; private set; }
  10. 10       
  11. 11                /// <summary>
  12. 12                /// this对象
  13. 13                /// </summary>
  14. 14                public object Instanse { get; private set; }
  15. 15       
  16. 16                /// <summary>
  17. 17                /// 方法参数列表
  18. 18                /// </summary>
  19. 19                public object[] Parameters { get; private set; }
  20. 20       
  21. 21                public DecoratorContext(Func<object, object[], object> invoker, object instanse, object[] parameters) {
  22. 22                    Invoker = invoker;
  23. 23                    Instanse = instanse;
  24. 24                    Parameters = parameters;
  25. 25                }
  26. 26            }
复制代码
然后需要完成的是DynamicTypeBuilder类,该类负责动态程序集,动态类型,动态方法的创建,具体实现如下:
  1. 01            internal class DynamicTypeBuilder {
  2. 02                //为动态程序集生成名称
  3. 03                private readonly string assemblyName = Guid.NewGuid().ToString();
  4. 04                //程序集主模块
  5. 05                private readonly string mainModuleName = "Main";
  6. 06       
  7. 07                public AssemblyBuilder AssemblyBuilder { get; private set; }
  8. 08       
  9. 09                public ModuleBuilder MainModuleBuilder { get; private set; }
  10. 10       
  11. 11                public DynamicTypeBuilder() {
  12. 12                    AssemblyName an = new AssemblyName(assemblyName);
  13. 13                    //构造一个可运行的动态程序集对象
  14. 14                    AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
  15. 15                    //为该程序集构造主模块
  16. 16                    MainModuleBuilder = AssemblyBuilder.DefineDynamicModule(mainModuleName);
  17. 17                }
  18. 18       
  19. 19                /// <summary>
  20. 20                /// 从Type类派生一个新的代理类
  21. 21                /// </summary>
  22. 22                /// <param name="type">基类</param>
  23. 23                /// <returns></returns>
  24. 24                public TypeBuilder CreateTypeBuilder(Type type) {
  25. 25                    TypeBuilder typeBuilder = MainModuleBuilder.DefineType(type.Name + "_" + Guid.NewGuid().ToString(),
  26. 26                        TypeAttributes.Class | TypeAttributes.Public,
  27. 27                        type);
  28. 28                    return typeBuilder;
  29. 29                }
  30. 30       
  31. 31                /// <summary>
  32. 32                /// 根据给定的方法对象和类型对象构造CodeGenerator
  33. 33                /// </summary>
  34. 34                /// <param name="typeBuilder"></param>
  35. 35                /// <param name="method"></param>
  36. 36                /// <returns></returns>
  37. 37                public CodeGenerator CreateMethodCodeGenerator(TypeBuilder typeBuilder, MethodInfo method) {
  38. 38                    CodeGenerator cg = new CodeGenerator(typeBuilder,
  39. 39                        method.Name,
  40. 40                        MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.HideBySig,
  41. 41                        CallingConventions.HasThis,
  42. 42                        method.ReturnType,
  43. 43                        method.GetParameters().Select(e => e.ParameterType).ToArray());
  44. 44                    typeBuilder.DefineMethodOverride(cg.CurrentMethod, method);
  45. 45                    return cg;
  46. 46                }
  47. 47        }
复制代码
赞助商
赞助商
TOP