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

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

    版权所有,欢迎转载
  • 相关阅读:
    如何锻炼出最牛程序员的编码套路
    如果仔细观察他们,你会发现他们时时都在锻炼
    单纯地每天埋头于工作并不能算是真正意义上的锻炼
    把全世界的人们都联系在一起,提升人们的社交参与度
    HTML5十五大新特性
    html5的八大特性
    【贪心】【二维偏序】【权值分块】bzoj1691 [Usaco2007 Dec]挑剔的美食家
    【分块】【链表】bzoj2738 矩阵乘法
    【分块】bzoj3343 教主的魔法
    【线段树】bzoj3747 [POI2015]Kinoman
  • 原文地址:https://www.cnblogs.com/xiaotie/p/1381825.html
Copyright © 2011-2022 走看看