• 动态方法与动态代理(下篇)


    动态代理:

      代理模式和装饰模式的区别:

      装饰模式:在不改变接口的前提下,动态扩展对象的功能

          代理模式:在不改变接口的前提下,控制对象的访问

          代理类和被代理对象是has-a关系,一般没有is-a关系,除非代理类直接继承被代理类,重写被代理类的方法

    动态代理是指通过动态代码技术在运行时生成具体类的代理,目的是在执行具体类的操作之前或之后运行特定的逻辑

    动态代理既可以代理类也可以代理接口,代理类时,被代理的类不能为Sealed,并且其中属性和方法都必须为Virtual,而代理接口时则无约束条件

     •Demo:动态生成接口的代理

    View Code
      1  public interface ICalculate
      2     {
      3         void Add(int a, int b);
      4     }
      5 
      6     public class A : ICalculate
      7     {
      8         #region ICalculate 成员
      9 
     10         public void Add(int a, int b)
     11         {
     12             Console.WriteLine(a + b);
     13         }
     14 
     15         #endregion
     16     }
     17 
     18     public class B : ICalculate
     19     {
     20         ICalculate _inst;
     21 
     22         public B(ICalculate o)
     23         {
     24             _inst = o;
     25         }
     26 
     27         #region ICalculate 成员
     28 
     29         public void Add(int a, int b)
     30         {
     31             Console.WriteLine("Before...");
     32             _inst.Add(a, b);
     33             Console.WriteLine("After...");
     34         }
     35 
     36         #endregion
     37     }
     38 
     39     class Program
     40     {
     41         static void Main(string[] args)
     42         {
     43             Type proxyType;//代理类型
     44 
     45             #region Emit Class
     46 
     47             AssemblyName assemblyName = new AssemblyName("DynamicAssemblyExample");
     48             AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
     49             ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll");
     50 
     51             TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicAssemblyExample.Calculate", TypeAttributes.Public | TypeAttributes.Class
     52                 , typeof(object), new Type[] { typeof(ICalculate) });
     53 
     54             FieldBuilder instanceField = typeBuilder.DefineField("_instance"typeof(ICalculate), FieldAttributes.Private);
     55 
     56             ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(ICalculate) });
     57 
     58             ILGenerator ilGenConstructor = constructorBuilder.GetILGenerator();
     59             ilGenConstructor.Emit(OpCodes.Ldarg_0);
     60             ilGenConstructor.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); //base.ctor()
     61             ilGenConstructor.Emit(OpCodes.Ldarg_0);
     62             ilGenConstructor.Emit(OpCodes.Ldarg_1);
     63             ilGenConstructor.Emit(OpCodes.Stfld, instanceField);
     64             ilGenConstructor.Emit(OpCodes.Ret);
     65 
     66             MethodInfo addMethodInfo = typeof(ICalculate).GetMethod("Add");
     67 
     68             MethodAttributes methodAttr = addMethodInfo.Attributes & ~(MethodAttributes.Abstract);
     69 
     70             List<Type> paramTypes = new List<Type>();
     71 
     72             foreach (ParameterInfo pInfo in addMethodInfo.GetParameters())
     73             {
     74                 paramTypes.Add(pInfo.ParameterType);
     75             }
     76 
     77             MethodBuilder addMethod = typeBuilder.DefineMethod(addMethodInfo.Name, methodAttr,
     78                 CallingConventions.Standard, addMethodInfo.ReturnType, paramTypes.ToArray());
     79 
     80             //writeline call
     81             MethodInfo writeLineMethod = typeof(Console).GetMethod("WriteLine"new Type[] { typeof(string) });
     82 
     83             ILGenerator ilGenAddMethod = addMethod.GetILGenerator();
     84 
     85 
     86             ilGenAddMethod.Emit(OpCodes.Ldstr, "Before...");
     87             ilGenAddMethod.Emit(OpCodes.Call, writeLineMethod);
     88 
     89             //每个实例方法都默认包含一个隐藏的参数,即第0个参数,它对应的是this指针,但静态方法没有隐藏的第0个参数
     90             ilGenAddMethod.Emit(OpCodes.Ldarg_0);
     91             ilGenAddMethod.Emit(OpCodes.Ldfld, instanceField);
     92 
     93             
     94             ilGenAddMethod.Emit(OpCodes.Ldarg_1);//a
     95             ilGenAddMethod.Emit(OpCodes.Ldarg_2);//b
     96             ilGenAddMethod.Emit(OpCodes.Callvirt, typeof(ICalculate).GetMethod("Add"));//a+b
     97 
     98             ilGenAddMethod.Emit(OpCodes.Ldstr, "After...");
     99             ilGenAddMethod.Emit(OpCodes.Call, writeLineMethod);
    100 
    101             /*
    102              * Console.WriteLine(this.GetType().FullName);
    103              */
    104             ilGenAddMethod.DeclareLocal(typeof(int));
    105             ilGenAddMethod.Emit(OpCodes.Ldarg_0);
    106             ilGenAddMethod.Emit(OpCodes.Callvirt, typeof(object).GetMethod("GetType"));
    107             ilGenAddMethod.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("get_FullName"));
    108             ilGenAddMethod.Emit(OpCodes.Call, writeLineMethod);
    109 
    110 
    111             ilGenAddMethod.Emit(OpCodes.Ret);
    112 
    113             proxyType = typeBuilder.CreateType();
    114 
    115             assemblyBuilder.Save("DynamicAssemblyExample.dll");
    116             #endregion
    117 
    118             ICalculate proxyImp = (ICalculate)proxyType.GetConstructor(new Type[] { typeof(ICalculate) })
    119                 .Invoke(new object[] { new A() });
    120 
    121             proxyImp.Add(1020);
    122         }
    123     }

     AOP的概念

      •Aspect Oriented Programming
      •AOP是OOP的延续,意思是面向切面编程
      •切面是指整体中的某个行为(功能)部分
      •目标:将与主逻辑无紧密关系的行为,从业务逻辑代码中分离出来
      •优点:当改变某个行为时,不会影响到业务逻辑,并且使代码进一步解耦
      •常用于日志记录,性能统计,安全控制,事务处理,异常处理等等
    AOP的工作原理 
    •AOP的关键是拦截正常的方法调用,即将需要额外附加的功能透明的“织入( Weave)”到这些方法中
    •所谓“织入”简单的讲就是指将附件功能和目标的原有功能融合在一起,AOP像一台织布机,将两者天衣无缝的编织起来,织入是透明的
    •在.Net中,AOP的织入方式有两种:

       静态织入:在编译阶段将附加逻辑写入代码中

       动态织入:在运行阶段将附加逻辑写入代码中 

      •静态织入:一般都需要扩展编译器的功能,优点是代码执行的效率高,缺点是实现者需要对虚拟机有很深的了解,而且修改代码之后都需要重新编译,目前,最著名的产品是:PostSharp
      •动态织入:不需要扩展编译器的功能,优点是在运行时自动生成代码,缺点是执行效率不高,需要额外的开销,目前,运用动态织入方法的产品较多,Castle.DynamicProxy是其中的经典之一

       动态织入的实现技术就是动态代理,由于静态织入存在局限性,一般来说,AOP框架实现方式首选动态织入,因此,AOP可以看作是动态代理发展的产物

     •Demo:AOP实践Castle.DynamicProxy

    这是一个轻量级的,能为一个或多个接口或具体类创建动态代理的类库,或者称之为AOP类库内部机制是使用反射发出动态织入
    拦截器( Interceptor)是其中的重要概念,用于截获方法的调用,增加新的逻辑,自定义拦截器必须实现IInterceptor接口或者继承内置的标准拦截器类StandardInterceptor拦截器对方法和属性都有效

    典型应用:
       参数检验
       延迟加载(Lazy Loading)
    典型代表:
       NHibernate

    View Code
     1  class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             DemoClassInterceptorTest.DoTest();
     6 
     7             //DemoInterfaceInterceptorTest.DoTest();
     8         }
     9     }
    10 public interface IDemoInterface
    11     {
    12         void Add(int a, int b);
    13     }
    14 
    15     public class DemoInterfaceClass : IDemoInterface
    16     {
    17         #region DemoInterface 成员
    18 
    19         public void Add(int a, int b)
    20         {
    21             Console.WriteLine(a + b);
    22         }
    23 
    24         #endregion
    25     }
    26 
    27     public class DemoInterfaceInterceptor : StandardInterceptor
    28     {
    29         protected override void PreProceed(IInvocation invocation)
    30         {
    31             Console.WriteLine("PreProceed:{0}", invocation.Method.ToString());
    32         }
    33 
    34         protected override void PostProceed(IInvocation invocation)
    35         {
    36             Console.WriteLine("PostProceed:{0}", invocation.Method.ToString());
    37         }
    38 
    39         protected override void PerformProceed(IInvocation invocation)
    40         {
    41             base.PerformProceed(invocation);
    42         }
    43     }
    44 
    45     public class DemoInterfaceInterceptorTest
    46     {
    47         public static void DoTest()
    48         {
    49             DemoInterfaceClass realObj = new DemoInterfaceClass();
    50 
    51             DemoInterfaceInterceptor interceptor = new DemoInterfaceInterceptor();
    52 
    53             ProxyGenerator generator = new ProxyGenerator();
    54             IDemoInterface proxy=generator.CreateInterfaceProxyWithTargetInterface<IDemoInterface>(realObj, interceptor);
    55             proxy.Add(1050);
    56         }
    57     }
    View Code
     1  public class DemoClass
     2     {
     3 
     4         string _text;
     5         public virtual string Text
     6         {
     7             get
     8             {
     9                 return _text;
    10             }
    11             set
    12             {
    13                 _text = value;
    14             }
    15         }
    16 
    17         public virtual void Add(int a, int b)
    18         {
    19             Console.WriteLine(a + b);
    20         }
    21     }
    22 
    23     class DemoClassInterceptor : IInterceptor
    24     {
    25         #region IInterceptor 成员
    26 
    27         /// <summary>
    28         /// Intercepts the specified invocation.
    29         /// </summary>
    30         /// <param name="invocation">The invocation.</param>
    31         public void Intercept(IInvocation invocation)
    32         {
    33             PreProceed(invocation);
    34             invocation.Proceed();
    35             PostProceed(invocation);
    36         }
    37 
    38         #endregion
    39 
    40         public void PreProceed(IInvocation invocation)
    41         {
    42             Console.WriteLine("PreProceed 1 代理了:{0}", invocation.Method.ToString());
    43         }
    44 
    45         public void PostProceed(IInvocation invocation)
    46         {
    47             Console.WriteLine("PostProceed 1 代理了:{0}", invocation.Method.ToString());
    48         }
    49     }
    50 
    51     class DemoClassInterceptor2 : IInterceptor
    52     {
    53         #region IInterceptor 成员
    54 
    55         /// <summary>
    56         /// Intercepts the specified invocation.
    57         /// </summary>
    58         /// <param name="invocation">The invocation.</param>
    59         public void Intercept(IInvocation invocation)
    60         {
    61             PreProceed(invocation);
    62             invocation.Proceed();
    63             PostProceed(invocation);
    64         }
    65 
    66         #endregion
    67 
    68         public void PreProceed(IInvocation invocation)
    69         {
    70             Console.WriteLine("PreProceed 2 代理了:{0}", invocation.Method.ToString());
    71         }
    72 
    73         public void PostProceed(IInvocation invocation)
    74         {
    75             Console.WriteLine("PostProceed 2 代理了:{0}", invocation.Method.ToString());
    76         }
    77     }
    78 
    79     class DemoClassInterceptorTest
    80     {
    81         public static void DoTest()
    82         {
    83             ProxyGenerator generator = new ProxyGenerator();
    84             DemoClassInterceptor interceptor = new DemoClassInterceptor();
    85             DemoClassInterceptor2 interceptor2 = new DemoClassInterceptor2();
    86             DemoClass obj = generator.CreateClassProxy<DemoClass>(interceptor, interceptor2);
    87             obj.Text = "test";
    88             obj.Add(1020);
    89         }
    90     }
  • 相关阅读:
    【转】XenServer的架构之Xenopsd组件架构与运行机制
    【转】XenServer架构之XAPI的调用流程
    关于JS面向对象、设计模式、以及继承的问题总结
    表格排序的具体案例(包括数字和汉字排序)
    call.apply.冒充对象继承
    ES6的学习之路(基础知识总结)
    ES6的基础知识总结
    JS预解释的总结
    函数执行的作用域问题
    JS中的闭包问题总结
  • 原文地址:https://www.cnblogs.com/dubing/p/2102208.html
Copyright © 2020-2023  润新知