zoukankan      html  css  js  c++  java
  • 实现.net下的动态代理

    一、动态代理可以解决哪些问题

     

    本文描述的动态代理可以解决以下问题:

     

    问题1:接口约束问题

     

    场景AComboBox类与ToolStripComboBox类的行为大部分相似,它们却不共享某个粒度较大的接口,以至于对这两个类的操作代码难以公用。

     

    场景B:在泛型程序中,我们必需为泛型类型声明一个接口约束,才能使用该类型所对应接口约束的方法与属性。这样以来有一个问题:存在接口A,类型BA中的所有属性和方法签名B都有,但B不是A的实现,不能由B转换为A。而由于某些原因,我们无法获得B的代码或者虽然能够获得B的代码,却由于种种考虑不能更改B的代码;

    大多数情况下,可以新写一个类C,使类C继承自B,再让C实现接口A。然而,其一,代码量较大;其二,当BSealed时不能继承;其三:不方便使用继承(如:继承后,IDE中的设计器无法给新类提供支持)。

     

    此时,我们希望动态代理能解决这个问题:

     

    假定我们有一个接口:

     

    1    public interface TInterface
    2    {
    3        String A get; }
    4        String B(Object a, Object b, Object c, Object d, Object e);
    5    }

    6

    有一个类:

     

     1    public class ClassA
     2    {
     3        public String A 
     4        {
     5            get
     6            {
     7                return String.Empty;
     8            }

     9        }

    10
    11        public String B(Object a, Object b, Object c, Object d, Object e)
    12        {
    13            return String.Empty;
    14        }

    15    }

    16
    17

    我们需要这个动态代理类(假定为 TypeTemplate)提供一个方法,能够方便的生成一个代理类实例,将ClassA的实例包装一下,转变为 TInterface 的实例:

     

    1        public static TInterface Create<TInterface, TImple>(TImple instance) 
    2            where TInterface : class
    3            where TImple : class
    4        {
    5            ……
    6        }

    7

    该方法生成一个实现TInterface的动态类的实例。对于TInterface中的每一个属性或方法,该实例直接调用instance实例中具有同样签名的属性或方法,如果没有匹配的属性或方法,则抛出NotImplementedException异常。

     

    问题2:快速生成现有实例类的Wrapper

     

    场景C:假定接口TInterface10个方法,类TImple中有9个方法与TInterface对应,为了实现TInterface,需要新写一个Wrapper类。最方便的写法是令Wrapper继承自TImple且实现接口TInterfaceWrapper只需新添实现那个未实现的方法即可。然而,如前面所述,很多情况下使用继承不是最佳选择。不用继承的话,则需要Wrapper类实现TInterface的全部10个方法,枯燥又乏味。

     

    此时,我们期待存在这样一种动态代理:它能够将几个实例BCD一起打包,使它适合接口A。这样一来,针对场景C,我们只需要写一个简单的Wrapper类,实现那个未实现的方法,然后与TImple实例一起由动态代理工厂打包生成一个新的代理类实例即可。

     

    即:我们需要动态代理工厂TypeTemplate能够提供以下方法:

     

    1        public static TInterface Create<TInterface>(TInterface instance, params Object[] impleInstances)
    2            where TInterface : class
    3        {
    4            …
    5        }

    6

     

    该方法生成一个实现TInterface的类实例。对于TInterface中的每一个属性或方法,该实例依次从impleInstances中寻找具有同样签名的属性或方法,如果没有匹配的属性或方法,则抛出NotImplementedException异常。

     

    问题3AOP应用

     

    场景D:当需要对方法进行拦截时我们需要动态代理。

     

    AOP是动态代理最经典的应用,无需赘述。

     

    这种情况下,我们需要 TypeTemplate 类提供以下的方法向代理类中加入钩子:

     

    1        public delegate void Handler<TImple>(TImple imple) where TImple: class;
    2
    3        public static TInterface CreateIntercepted<TInterface, TImple>(TImple instance, Handler<TImple> before, Handler<TImple> after)
    4            where TInterface : class
    5            where TImple : class
    6        {
    7            …
    8        }

    9

    二、实现

     

     

    下面来实现动态代理类工厂TypeTemplate。由于时间有限,只实现 static TInterface Create<TInterface, TImple>(TImple instance) 方法原型。其它几个静态方法可以用类似的方式实现。

     

    实现思路:

     

    对于问题1中的接口TInterface和类ClassA,通过Emit生成如下类型InterfaceImple_ClassAIL代码。

     

     1    public class InterfaceImple_ClassA : TInterface
     2    {
     3        private ClassA __wrappedInstance;
     4
     5        public InterfaceImple_ClassA(ClassA instance)
     6        {
     7            __wrappedInstance = instance;
     8        }

     9
    10        public String A
    11        {
    12            get return __wrappedInstance.A; }
    13            set throw new NotImplementedException(); }
    14        }

    15
    16        public String B(Object a, Object b, Object c, Object d, Object e)
    17        {
    18            return __wrappedInstance.B(a,b,c,d,e);
    19        }

    20    }

    21
    22

    假定生成上面这个类型的方法为:

     

    1        public static Type DynamicTypeGen<TInterface, TImple>()
    2            where TInterface: class where TImple : class
    3
    4

     

    则可用Activator轻松生成动态代理类实例:

     

    1        public static TInterface Create<TInterface, TImple>(TImple instance) 
    2            where TInterface : class
    3            where TImple : class
    4        {
    5            Type type = DynamicTypeGen<TInterface, TImple>();
    6            return Activator.CreateInstance(type, instance) as TInterface;
    7        }

    8

    下面是具体代码:

     

     

    Code

     

    单元测试代码:

     

     1        [TestMethod]
     2        public void TestCreate()
     3        {
     4            ClassA a = new ClassA();
     5            TInterface i = TypeTemplate.Create<TInterface, ClassA>(a);
     6            Assert.AreNotEqual(null, i);
     7            Assert.AreEqual(String.Empty, i.A);
     8            Assert.AreEqual("3", i.B(12));
     9        }

    10

     

     

    三、说明

     

    1         上文只是 TypeTemplate的原型实现,我只进行了简单的单元测试,没有针对全部可能遇见的情况进行测试;在功能上,未生成event的动态代理;

    2         static TInterface Create<TInterface>(TInterface instance, params Object[] impleInstances) 这个方法生成的代理类最好继承一个特殊接口,通过该接口能够接入被代理的实例;

    3         如果第一部分所述的三个静态方法全部实现了的话,将是一个非常强大的代理工厂;

    4         代理类实例的性能接近于直接调用相关方法或属性的性能,性能极佳;

    5         代理类实例的生成是通过反射生成的,在性能上有很大的提升空间。可以通过emit动态生成一个工厂类。如,针对上面的ClassA,生成如下工厂类:

     

    1    public class InterfaceImple_ClassA_Factory
    2    {
    3        public readonly String Name = "InterfaceImple_ClassA_Factory";
    4        public InterfaceImple_ClassA Create(ClassA a)
    5        {
    6            return new InterfaceImple_ClassA(a);
    7        }

    8    }

    9

             然后通过反射生成以上工厂类的实例,缓存住。当需要生成新的动态代理实例时,从缓存中查找对应的工厂,生成具体的代理类。

    版权所有,欢迎转载
  • 相关阅读:
    JDBC 复习4 批量执行SQL
    JDBC 复习3 存取Oracle大数据 clob blob
    Oracle复习
    Linux命令(1)grep
    JDBC 复习2 存取mysql 大数据
    JDBC 复习1 DBUtil
    php 环境搭建问题
    Windows 批处理 bat 开启 WiFi 菜单选项 设置ID PWD
    Bat 批处理启动和停止Oracle 服务
    docker 学习1 WSL docker ,Windows docker
  • 原文地址:https://www.cnblogs.com/xiaotie/p/1381825.html
Copyright © 2011-2022 走看看