閱讀734 返回首頁    go windows


一個簡單的小程序演示Unity的三種依賴注入方式

今天寫《WCF技術剖析(卷2)》關於《WCF擴展》一章,舉了“如何通過WCF擴展實現與IoC框架(以Unity為例)集成”(《通過自定義ServiceHost實現對WCF的擴展[實例篇]》)的例子。為了展示Unity如何實現幾種典型的注入方式(構造器注入、屬性注入和方法注入),我寫了一個簡單的小程序。如果讀者對Unity或者IoC沒有太多概念,我覺得這個小程序對於你初步地認識它們具有一定的幫助意義。如果你對Unity或者IoC有深入的認識,請忽略本文。[源代碼從這裏下載]

首先創建一個控製台程序,並添加如下兩個基於Unity的程序集被引用:Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll。然後定義如下幾個接口(IA、IB、IC和ID)和它們各自的實現類(A、B、C、D)。在類型A中定義了3個屬性B、C和D,其類型分別為接口IB、IC和ID。其中屬性B在構在函數中被初始化;屬性C上應用了Microsoft.Practices.Unity.DependencyAttribute特性,意味著這是一個需要以屬性注入方式被初始化的依賴屬性;屬性D則通過方法Initialize初始化,該方法上應用了Microsoft.Practices.Unity.InjectionMethodAttribute,意味著這是一個注入方法會被自動調用。

   1: namespace UnityDemo
   2: {
   3:     public interface IA { }
   4:     public interface IB { }
   5:     public interface IC { }
   6:     public interface ID {}
   7:  
   8:     public class A : IA
   9:     {
  10:         public IB B { get; set; }
  11:         [Dependency]
  12:         public IC C { get; set; }
  13:         public ID D { get; set; }
  14:  
  15:         public A(IB b)
  16:         {
  17:             this.B = b;
  18:         }
  19:         [InjectionMethod]
  20:         public void Initialize(ID d)
  21:         {
  22:             this.D = d;
  23:         }
  24:     }
  25:     public class B: IB{}
  26:     public class C: IC{}
  27:     public class D: ID{}
  28: }

然後我們為該應用添加一個配置文件,並定義如下一段關於Unity的配置。在這段配置中,定義了一個名稱為defaultContainer的Unity容器,並在其中完成了上麵定義的接口和對應實現類之間映射的類型匹配。

   1: <?xml version="1.0"?>
   2: <configuration>
   3:   <configSections>
   4:     <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
   5:   </configSections>
   6:   <unity>
   7:     <containers>
   8:       <container name="defaultContainer">
   9:         <register type="UnityDemo.IA, UnityDemo" mapTo="UnityDemo.A, UnityDemo"/>
  10:         <register type="UnityDemo.IB, UnityDemo" mapTo="UnityDemo.B, UnityDemo"/>
  11:         <register type="UnityDemo.IC, UnityDemo" mapTo="UnityDemo.C, UnityDemo"/>
  12:         <register type="UnityDemo.ID, UnityDemo" mapTo="UnityDemo.D, UnityDemo"/>
  13:       </container>
  14:     </containers>
  15:   </unity> 
  16: </configuration>

最後在Main方法中編寫如下的程序:創建一個代表IoC容器的UnityContainer對象,並加載配置信息對其進行初始化。然後調用它的泛型的Resolve方法創建一個實現了泛型接口IA的對象。最後將返回對象轉變成類型A,並檢驗其B、C和D屬性是否是空。

   1: static void Main(string[] args)
   2: {
   3:     IUnityContainer container = new UnityContainer();
   4:     UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
   5:     configuration.Configure(container, "defaultContainer");
   6:     A a = container.Resolve<IA>() as A;
   7:     if (null != a)
   8:     {
   9:         Console.WriteLine("a.B == null ? {0}", a.B == null ? "Yes" : "No");
  10:         Console.WriteLine("a.C == null ? {0}", a.C == null ? "Yes" : "No");
  11:         Console.WriteLine("a.D == null ? {0}", a.D == null ? "Yes" : "No");
  12:     }
  13: }

從如下給出的執行結果我們可以得到這樣的結論:通過Resolve<IA>方法返回的是一個類型為A的對象;該對象的三個屬性被進行了有效的初始化。這個簡單的程序分別體現了接口注入(通過相應的接口根據配置解析出相應的實現類型)、構造器注入(屬性B)、屬性注入(屬性C)和方法注入(屬性D)。

   1: a.B == null ? No
   2: a.C == null ? No
   3: a.D == null ? No

關於IoC/DI

所謂控製反轉(IoC: Inversion Of Control)就是應用本身不負責依賴對象的創建和維護,而交給一個外部容器來負責。這樣控製權就由應用轉移到了外部IoC容器,控製權就實現了所謂的反轉。比如,在類型A中需要使用類型B的實例,而B實例的創建並不由A來負責,而是通過外部容器來創建。

有時我們又將IoC成為依賴注入(DI: Dependency Injection)。所謂依賴注入,就是由外部容器在運行時動態地將依賴的對象注入到組件之中。具體的依賴注入方式又包括如下三種典型的形式。

  • 構造器注入(Constructor Injection):IoC容器會智能地選擇選擇和調用適合的構造函數以創建依賴的對象。如果被選擇的構造函數具有相應的參數,IoC容器在調用構造函數之前會自定義創建相應參數對象;
  • 屬性注入(Property Injection):如果需要使用到被依賴對象的某個屬性,在被依賴對象被創建之後,IoC容器會自動初始化該屬性;
  •  方法注入(Method Injection):如果被依賴對象需要調用某個方法進行相應的初始化,在該對象創建之後,IoC容器會自動調用該方法。

在開源社區,具有很有流行的IoC框架,比如Castle Windsor、Unity、Spring.NET、StructureMap、Ninject等。


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-26 16:04:18

  上一篇:go  通過自定義ServiceHost實現對WCF的擴展[實例篇]
  下一篇:go  WCF運行時框架的構建與擴展[共10篇]