.NET:動態代理的 “5 + 1” 模式


背景

什么叫“動態代理”,代理模式我們都知道,動態代理就是動態生成的代理(采用Emit)。

重量級的ORM和IOC產品離不開動態代理,作為開發人員,多數情況不用關注動態代理的內部實現機制,但是了解其一般的規律和模式還是有必要的,比如:雖然你開發期間采用了POCO,因為開啟了動態代理,運行期間則不是POCO。

本文簡單描述了5種代理生成模式和1種Mixin模式,最后給出一個示例。

公共代碼

這里先給出公共代碼。

 1     public interface IPlayable
 2     {
 3         void Play();
 4     }
 5 
 6     public class Animal : IPlayable
 7     {
 8         public virtual void Play()
 9         {
10             Console.WriteLine("Animal.Play");
11         }
12     }
13 
14     public class Dog : Animal
15     {
16         public override void Play()
17         {
18             Console.WriteLine("Dog.Play");
19         }
20     }
21 
22     public interface IRunable
23     {
24         void Run();
25     }
26 
27     public class RunAbility : IRunable
28     {
29         public void Run()
30         {
31             Console.WriteLine("RunAbility.Run");
32         }
33     }
34 
35     public class AnimalInterceptor : IInterceptor
36     {
37         public void Intercept(IInvocation invocation)
38         {
39             Console.WriteLine("Before AnimalInterceptor.Intercept");
40             if (invocation.InvocationTarget != null)
41             {
42                 invocation.Proceed();
43             }
44             Console.WriteLine("After AnimalInterceptor.Intercept");
45         }
46     }

5種代理模式

第一種:ClassProxy

代碼示例

 1             {
 2                 Console.WriteLine("\n*************ClassProxy*************\n");
 3                 var generator = new ProxyGenerator();
 4                 var animal = generator.CreateClassProxy<Animal>(new AnimalInterceptor());
 5                 animal.Play();
 6 
 7                 Console.WriteLine(animal.GetType());
 8                 Console.WriteLine(animal.GetType().BaseType);
 9 
10                 var compositeField = animal.GetType().GetField("__target");
11                 Console.WriteLine(compositeField);
12 
13                 foreach (var interfaceType in animal.GetType().GetInterfaces())
14                 {
15                     Console.WriteLine(interfaceType);
16                 }
17             }

運行結果

動態代理類圖

等待上傳中。

第二種:ClassProxyWithTarget

代碼示例

 1             {
 2                 Console.WriteLine("\n*************ClassProxyWithTarget*************\n");
 3                 var generator = new ProxyGenerator();
 4                 var animal = generator.CreateClassProxyWithTarget<Animal>(new Dog(), new AnimalInterceptor());
 5                 animal.Play();
 6 
 7                 Console.WriteLine(animal.GetType());
 8                 Console.WriteLine(animal.GetType().BaseType);
 9 
10                 var compositeField = animal.GetType().GetField("__target");
11                 Console.WriteLine(compositeField);
12 
13                 foreach (var interfaceType in animal.GetType().GetInterfaces())
14                 {
15                     Console.WriteLine(interfaceType);
16                 }
17             }

運行結果

動態代理類圖

等待上傳中。

第三種:InterfaceProxyWithoutTarget

代碼示例

 1             {
 2                 Console.WriteLine("\n*************InterfaceProxyWithoutTarget*************\n");
 3                 var generator = new ProxyGenerator();
 4                 var animal = generator.CreateInterfaceProxyWithoutTarget<IPlayable>(new AnimalInterceptor());
 5                 animal.Play();
 6 
 7                 Console.WriteLine(animal.GetType());
 8                 Console.WriteLine(animal.GetType().BaseType);
 9 
10                 var compositeField = animal.GetType().GetField("__target");
11                 Console.WriteLine(compositeField);
12 
13                 foreach (var interfaceType in animal.GetType().GetInterfaces())
14                 {
15                     Console.WriteLine(interfaceType);
16                 }
17             }

運行結果

動態代理類圖

等待上傳中。

第四種:InterfaceProxyWithTarget

測試代碼

 1             {
 2                 Console.WriteLine("\n*************InterfaceProxyWithTarget*************\n");
 3                 var generator = new ProxyGenerator();
 4                 var animal = generator.CreateInterfaceProxyWithTarget<IPlayable>(new Dog(), new AnimalInterceptor());
 5                 animal.Play();
 6 
 7                 Console.WriteLine(animal.GetType());
 8                 Console.WriteLine(animal.GetType().BaseType);
 9 
10                 var compositeField = animal.GetType().GetField("__target");
11                 Console.WriteLine(compositeField);
12 
13                 foreach (var interfaceType in animal.GetType().GetInterfaces())
14                 {
15                     Console.WriteLine(interfaceType);
16                 }
17             }

運行結果

動態代理類圖

等待上傳中。

第五種:InterfaceProxyWithTargetInterface

測試代碼

 1             {
 2                 Console.WriteLine("\n*************InterfaceProxyWithTargetInterface*************\n");
 3                 var generator = new ProxyGenerator();
 4                 var animal = generator.CreateInterfaceProxyWithTargetInterface<IPlayable>(new Dog(), new AnimalInterceptor());
 5                 animal.Play();
 6 
 7                 Console.WriteLine(animal.GetType());
 8                 Console.WriteLine(animal.GetType().BaseType);
 9 
10                 var compositeField = animal.GetType().GetField("__target");
11                 Console.WriteLine(compositeField);
12 
13                 foreach (var interfaceType in animal.GetType().GetInterfaces())
14                 {
15                     Console.WriteLine(interfaceType);
16                 }
17             }

運行結果

動態代理類圖

等待上傳中。

1種Mixin模式

測試代碼

 1             {
 2                 Console.WriteLine("\n*************Mixin*************\n");
 3                 var generator = new ProxyGenerator();
 4                 var options = new ProxyGenerationOptions();
 5                 options.AddMixinInstance(new RunAbility());
 6                 var animal = generator.CreateClassProxy<Animal>(options, new AnimalInterceptor());
 7                 animal.Play();
 8                 (animal as IRunable).Run();
 9 
10                 Console.WriteLine(animal.GetType());
11                 Console.WriteLine(animal.GetType().BaseType);
12 
13                 var compositeField = animal.GetType().GetField("__target");
14                 Console.WriteLine(compositeField);
15 
16                 foreach (var field in animal.GetType().GetFields())
17                 {
18                     if (field.Name.StartsWith("__mixin"))
19                     {
20                         Console.WriteLine(field);
21                     }
22                 }
23 
24                 foreach (var interfaceType in animal.GetType().GetInterfaces())
25                 {
26                     Console.WriteLine(interfaceType);
27                 }
28             }

運行結果

動態代理類圖

等待上傳中。

動態代理在DCI中的應用

參考鏈接:http://www.cnblogs.com/happyframework/archive/2013/04/25/3040461.html#content_4

經常見到的動態代理場景

  1. ORM延時加載。
  2. AOP攔截(不全是使用的動態代理,有的使用透明代理或字節碼增強,有的使用平台自帶的管道過濾器,如:ASP.NET MVC的FilterAction)。
  3. WCF客戶端代理。

備注

了解了這些模式后,自己開發一個簡單的動態代理模式應該不是問題了,如果是C#語言,得學好Emit(不是那么簡單),如果是Ruby的話,估計就非常Easy了,找個機會給出這兩種語言的不同實現。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM