程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> Unity依賴注入使用詳解

Unity依賴注入使用詳解

編輯:C#入門知識

寫在前面

控制反轉(Inversion of Control)和依賴注入(Dependency Injection)大家網上可以找下相關概念,在小菜學習設計模式(五)—控制反轉(Ioc)》這篇文章中本人也有詳細的解釋,這邊再說明下,有很多人把控制反轉和依賴注入混為一談,雖然在某種意義上來看他們是一體的,但好像又有些不同,就比如在上篇文章中所提到的示例。控制反轉(Ioc)可以看成自來水廠,那自來水廠的運行就可以看作依賴注入(DI),Ioc是一個控制容器,DI就是這個容器的運行機制,有點像國家主席和總理的意思。

添加,也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll,下面我們就一步一步的學習下的詳細使用。

構造器注入

View Code

,在的抽象,我們看下調用代碼:

           Main(              UnityContainer container =  UnityContainer();
             container.RegisterType<Test01.IWaterTool, Test01.PressWater>();
             Test01.IPeople people = container.Resolve<Test01.VillagePeople>();
             people.DrinkWater();
         }

方法簽名:

View Code

this IUnityContainer container,我們上面調用的時候並沒有傳遞一個IUnityContainer 類型的參數,為什麼這裡會有一個this關鍵字,做什麼用?其實這就是擴展方法。這個擴展方法在靜態類中聲明,定義一個靜態方法(UnityContainerExtensions類和RegisterType都是靜態的),其中第一個參數定義可它的擴展類型。RegisterType方法擴展了UnityContainerExtensions類,因為它的第一個參數定義了IUnityContainer(UnityContainerExtensions的抽象接口)類型,為了區分擴展方法和一般的靜態方法,擴展方法還需要給第一個參數使用this關鍵字。

TTo依賴於TFrom。

View Code

Dependency屬性注入

只需要在屬性字段前面加[Dependency]標記就行了,如下:

          
                   
                          IWaterTool _pw { ;                           }

方法注冊,我們還可以在配置文件中注冊,方式其實都會產生耦合度,我們要添加一個屬性或是修改一中注冊都會去修改代碼,我們要做的就是代碼不去修改,只要修改配置文件了,這個在下面有講解,這邊就不多說,我們先看下使用UnityConfigurationSection的Configure方法加載配置文件注冊:

   
     
       
         
         
       
     
   

                         UnityContainer container =  UnityContainer();
             UnityConfigurationSection configuration =             configuration.Configure(container,              IPeople people = container.Resolve<IPeople>();
             people.DrinkWater();
         }

InjectionMethod方法注入

只需要在方法前加[InjectionMethod]標記就行了,從方法注入的定義上看,只是模糊的說對某個方法注入,並沒有說明這個方法所依賴的對象注入,所依賴的對象無非就三種:參數、返回值和方法內部對象引用,我們做一個示例試下:

      
           
                 IWaterTool tool;
          IWaterTool tool2;
          IWaterTool tool3;
                          (tool ==                            .tool2 =                               }

                         UnityContainer container =  UnityContainer();
             UnityConfigurationSection configuration =             configuration.Configure(container,              VillagePeople03 people = container.Resolve<IPeople>()  VillagePeople03;
             Console.WriteLine(, people.tool ==  ?  :              Console.WriteLine(, people.tool2 ==  ?  :              Console.WriteLine(, people.tool3 ==  ?  :          }

VillagePeople03;其實多此一舉,因為已經在配置文件注冊過了,不需要再進行轉化,這邊只是轉化只是方便訪問VillagePeople03對象的幾個屬性值,我們看下運行效果:

下面會講到。

非泛型注入

                         UnityContainer container =  UnityContainer();
             container.RegisterType((IWaterTool), (PressWater));
             IPeople people = (IPeople)container.Resolve((VillagePeople01));
             people.DrinkWater();
         }

標識鍵

 container.RegisterType<IWaterTool, PressWater>();

                         UnityContainer container =  UnityContainer();
             container.RegisterType<IWaterTool, PressWater>();
             container.RegisterType<IWaterTool, PressWater>();
             IWaterTool wt = container.Resolve<IWaterTool>();
              list = container.ResolveAll<IWaterTool>();
         }

ContainerControlledLifetimeManager單例

這篇文章,為了實現單例模式,我們通常的做法是,在類中定義一個方法如GetInstance,判斷如果實例為null則新建一個實例,否則就返回已有實例。但是我覺得這種做法將對象的生命周期管理與類本身耦合在了一起。所以我覺得遇到需要使用單例的地方,應該將生命周期管理的職責轉移到對象容器Ioc上,而我們的類依然是一個干淨的類,使用Unity創建單例代碼:

                         UnityContainer container =  UnityContainer();
             container.RegisterType<IWaterTool, PressWater>( ContainerControlledLifetimeManager());
             IPeople people = container.Resolve<VillagePeople01>();
             people.DrinkWater();
         }

 container.RegisterType<PressWater>( ContainerControlledLifetimeManager());

 PressWater pw =  container.RegisterInstance<IWaterTool>(pw);

,類型注冊後,我們再次獲取的對象就是上次創建的對象,而不是再重新創建對象,這也就是單例的意思。

Unity注冊配置問題

   
     
       
         
         
       
     
   

Unity的app.config節點配置

View Code

  • container集合,我們可以配置多個容器類型,通過Name屬性就可以訪問,比如訪問defaultContainer容器代碼:configuration.Configure(container, "defaultContainer");

unity版本問題,unity2.0配置文件中並沒有typeConfig節點,而我們使用的unity程序集是最新的,而並沒有識別typeConfig節點,這個問題很嚴重,也花了我兩天時間,就像那位提問者最後所說:“I can not tell you how grateful I am, I've spent the last 2 days trying to figure this one out.”,雖然問題原因找到了,但是是通過英文搜索找到了,就是說國外遇到過類似問題,難道我們國內沒有遇到過,郁悶。

  大家可能有些納悶,為什麼你上面幾個示例使用的unity配置沒有報錯,我當時在寫示例的時候只是使用簡單的類型映射,並不是使用完整的unity配置文件,然後就網上找了下,就找到了msdn.microsoft.com/en-us/library/ff647848.aspx,當時沒有注意版本問題,所以就出現了上面的問題,我們上面示例unity配置文件中Register節點就是unity2.0的配置,這也是為什麼上面示例可以運行的原因。

  unity2.0的配置文件配置說明找了好久,終於在MSDN找到了:http://msdn.microsoft.com/en-us/library/ff660914%28v%3Dpandp.20%29.aspx#config_constructor,沒有中文版本,英文不好的朋友可以使用Google簡單翻譯下,注意這段話“Unity 2.0 uses a new streamlined configuration schema for configuring Unity.”,這才是我們要使用的unity2.0的配置文件,其實和1.2版本差不多,只不過是簡化了一些東西,配置起來也更加方便,這邊就不多說了,列一下配置目錄:

  在unity1.2中我們使用構造器注入、屬性注入和方法注入會有parameterType節點,就是說在constructor、property和method這些節點可以配置這些方式注入所依賴的類型,但是在unity2.0並不存在parameterType節點了,所有類型注冊都是通過register節點進行配置的,相當於unity1.2中的type節點,雖然unity2.0存在constructor、property和method節點,但我感覺只是針對構造器、屬性和方法本身進行注入。

   
     
       
          
       
       
     
   
   

unity1.2中創建下面節點:

  

後記

  本篇中的代碼稍微整理了下,有興趣的朋友可以下載看看,地址:http://pan.baidu.com/s/1pJAtdoR

Unity依賴注入的東西,也是擴充Unity的中文資料。

  另外插一句,我在寫博客的時候喜歡在草稿箱浏覽很多次,不管是內容上或是排版字體上,寫一段,浏覽一段,修改一段,有點小強迫症哈,但是是對自己負責,也是對別人負責。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved