代码改变世界

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

2011-07-10 12:11  熬夜的虫子  阅读(520)  评论(0编辑  收藏  举报

动态代理:

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

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

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

      代理类和被代理对象是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     }