[EntLib]微軟企業庫5.0 學習之路——第十步、使用Unity解耦你的系統—PART2——瞭解Unity的使用方法(3)

[EntLib]微軟企業庫5.0 學習之路——第十步、使用Unity解耦你的系統—PART2——瞭解Unity的使用方法(3)

      今天繼續介紹Unity,在上一篇的文章中,我介紹了使用UnityContainer來註冊對象之間的關係、註冊已存在的對象之間的關係,同時着重介紹 了Unity內置的各種生命週期管理器的使用方法,今天則主要介紹Unity的Register和Resolve的一些高級應用。

本篇文章將主要介紹:

1、註冊類型同時初始化構造函數參數並重載調用。

2、註冊類型同時初始化屬性參數並重載調用。

3、延遲獲取對象。

4、檢索檢索容器中註冊信息。

 

一、註冊類型同時初始化構造函數參數並重載調用

      我們在使用Unity中註冊對象之間的關係時,可能對象有相應的構造函數,構造函數中需要傳遞相應的參數,Unity就支持這樣的註冊,其主要靠InjectionConstructor這個類來完成,我們首先來看下具體的類構造函數:

1 public YourClass( string test, MyClass my)
2 {
3      Console.WriteLine(test);
4      Console.WriteLine(my.ToString());
5 }

這個構造函數有2個參數,一個字符串和一個MyClass類對象,相應的可以使用如下代碼進行註冊:

1 //由於所註冊的對象的有帶有參數的構造函數,所以註冊類型時需要提供相應的參數
2 //這邊採用InjectionConstructor這個類來實現
3 container.RegisterType<IClass, YourClass>(
4      new InjectionConstructor( "a" , new MyClass()));
5 Console.WriteLine( "-----------默認調用輸出-------------" );
6 container.Resolve<IClass>();

這樣既可完成對象註冊的同時對構造函數參數進行注入,此時還有另外一個需求,就是雖然在註冊的時候已經對構造函數參數進行了初始化,但是在調用的時候我們想更換原先註冊的值,這時應該怎麼辦?

在Unity中,已經幫我們解決了這個問題,我們可以通過ParameterOverride和ParameterOverrides來實現,其中 ParameterOverride是針對一個參數,而ParameterOverrides是針對參數列表,有關注冊參數初始化及參數重載的全部代碼如 下:

01 public static void ResolveParameter()
02 {
03      //由於所註冊的對象的有帶有參數的構造函數,所以註冊類型時需要提供相應的參數
04      //這邊採用InjectionConstructor這個類來實現
05      container.RegisterType<IClass, YourClass>(
06          new InjectionConstructor( "a" , new MyClass()));
07      Console.WriteLine( "-----------默認調用輸出-------------" );
08      container.Resolve<IClass>();
09  
10      Console.WriteLine( "-----------重載後調用輸出-------------" );
11      //以下2種Resolve方法效果是一樣的
12      //對於參數過多的時候可以採用第2種方法,如果參數僅僅只有1個可以用第1種
13      //container.Resolve<IClass>(new ParameterOverride("test", "test"),
14      //    new ParameterOverride("my", "new MyClass").OnType<MyClass>());
15      container.Resolve<IClass>( new ParameterOverrides()
16      {
17          { "test" , "test" },
18          { "my" , new MyClass()}
19      }.OnType<YourClass>());
20 }

其中需要注意的是:

1、在使用ParameterOverride方法來重載參數時,如果註冊的參數是一個具體的對象就需要使用OnType這個擴展方法來指定對應的類型,否則會報錯。

2、在使用ParameterOverrides進行重載參數時,可以使用如上面代碼的方式進行指定,但是同樣需要使用OnType來指定,不過這個的OnType指定的類型是註冊的對象類型。

效果圖如下:

pic78

可以看出,其中第一個字符串參數在重載後調用時已經發生了更改。

 

二、註冊類型同時初始化屬性並重載調用

     這個初始化屬性和上面的初始化參數很類似,只不過不同的是,屬性的註冊初始化是使用InjectionProperty,而重載屬性是使用的 PropertyOverride和PropertyOverrides,其使用方法也是相同的,這邊就不多介紹了,代碼如下:

01 public static void ResolveProperty()
02 {
03      //註冊對象關係時初始化對象的屬性
04      container.RegisterType<IClass, MyClass>(
05          new InjectionProperty( "Name" , "A班" ),
06          new InjectionProperty( "Description" , "A班的描述" ));
07      Console.WriteLine( "-----------默認調用輸出-------------" );
08      Console.WriteLine(container.Resolve<IClass>().Name);
09      Console.WriteLine(container.Resolve<IClass>().Description);
10      Console.WriteLine( "-----------重載後調用輸出-------------" );
11      //以下2種寫法效果是一樣的,同上面的構造函數參數重載
12      //var myClass = container.Resolve<IClass>(new PropertyOverride("Name", "重載後的A班"),
13      //    new PropertyOverride("Description", "重載後的A班的描述"));
14      var myClass = container.Resolve<IClass>( new PropertyOverrides()
15      {
16          { "Name" , "重載後的A班" },
17          { "Description" , "重載後的A班的描述" }
18      }.OnType<MyClass>());
19  
20      Console.WriteLine(myClass.Name);
21      Console.WriteLine(myClass.Description);
22 }

效果圖如下:

pic79

可以看到2個屬性都已經被重載了。

Unity還爲我們提供了一個DependencyOverride重載,其使用方法和參數重載、屬性重載類似,這邊就不演示了,不過需要注意的是DependencyOverride是針對所註冊對象類型中所包含的對象類型重載,例如在A類中有構造函數參數是B類,同時也有個屬性依賴於B類,當使用了DependencyOverride後,這個A對象原先註冊的有關B類的依賴將全部改變 。(具體可查看示例代碼中的ResolveDependency)

 

三、延遲獲取對象

     Unity還有個很不錯的特性就是支持延遲獲取, 其本質是通過事先建立一個委託,然後再調用這個委託,看下下面的代碼:

01 public static void DeferringResolve()
02 {
03      var resolver = container.Resolve<Func<IClass>>();
04  
05      //根據業務邏輯做其他事情。
06  
07      //註冊IClass與MyClass之間的關係
08      container.RegisterType<IClass, MyClass>();
09      //獲取MyClass實例
10      var myClass = resolver();
11  
12      var resolver2 = container.Resolve<Func<IEnumerable<IClass>>>();
13  
14      //根據業務邏輯做其他事情。
15  
16      //註冊與IClass相關的對象。
17      container.RegisterType<IClass, MyClass>( "my" );
18      container.RegisterType<IClass, YourClass>( "your" );
19      //獲取與IClass關聯的所有命名實例
20      var classList = resolver2();
21 }

這段代碼演示了2個延遲獲取的方式,都是通過將Func<T>放入Resolve<T>中來實現的,返回的是一委託,這樣就可以在實際需要的時候再調用這個委託:

1、第一種是事先通過Resolve<Func<IClass>>(); 來定義獲取與IClass關聯的對象的委託,然後再註冊IClass與MyClass之間的關係,然後再通過resolver(); 來獲取。

2、第二種是事先通過Resolve<Func<IEnumerable<IClass>>>(); 來定義獲取一個與IClass關聯的命名實例列表的委託,然後調用相應的委託就可以一次性獲取與IClass關聯的所有命名實例。

這2種方式都很好的展示了Unity可以更加靈活的控制對象之間的註冊與對象的調用。

 

四、檢索容器中註冊信息

      當我們在不斷使用Unity容器的過程中,我們有時候想看一下容器中到底註冊了多少對象,以及各個對象的一些信息,如:什麼對象和什麼對象關聯、具體的注 冊名稱和使用的生命週期管理器,這些信息都可以在容器的Registrations屬性中查看到,在Unity文檔中已經有個方法來查看這些信息了,代碼 如下:

01 public static void DisplayContainerRegistrations(IUnityContainer theContainer)
02 {
03      string regName, regType, mapTo, lifetime;
04      Console.WriteLine( "容器中 {0} 個註冊信息:" ,
05              theContainer.Registrations.Count());
06      foreach (ContainerRegistration item in theContainer.Registrations)
07      {
08          regType = item.RegisteredType.Name;
09          mapTo = item.MappedToType.Name;
10          regName = item.Name ?? "[默認]" ;
11          lifetime = item.LifetimeManagerType.Name;
12          if (mapTo != regType)
13          {
14              mapTo = " -> " + mapTo;
15          }
16          else
17          {
18              mapTo = string .Empty;
19          }
20          lifetime = lifetime.Substring(0, lifetime.Length - "生命週期管理器" .Length);
21          Console.WriteLine( "+ {0}{1}  '{2}'  {3}" , regType, mapTo, regName, lifetime);
22      }
23 }

具體的註冊代碼如下:

01 public static void RegisterAll()
02 {
03      container.RegisterType<IClass, MyClass>( "my" );
04      container.RegisterType<IClass, YourClass>( "your" ,
05          new ExternallyControlledLifetimeManager());
06      container.RegisterType<ISubject, Subject1>( "subject1" );
07      container.RegisterType<ISubject, Subject2>( "subject2" );
08  
09      DisplayContainerRegistrations(container);
10 }

效果圖如下:

pic80

可以看到,我在代碼中註冊的信息都已經很好的反應出來了。

同時如果想查看某個對象是否已經被註冊,可以通過container.IsRegistered<T>來驗證,這邊就不演示了。

 

以上就是本文的所有內容了,主要介紹了Unity的Register和Resolve的一些高級應用,英文好的朋友可以直接查看Unity的官方文檔。

 

示例代碼下載:點我下載

注意:本文示例代碼是基於VS2010+Unity2.0,所以請使用VS2010打開,如果沒有安裝VS2010,請將相關代碼複製到相應的VS中運行既可

 

微軟企業庫5.0 學習之路系列文章索引:

第一步、基本入門

第二步、使用VS2010+Data Access模塊建立多數據庫項目

第三步、爲項目加上異常處理(採用自定義擴展方式記錄到數據庫中)

第四步、使用緩存提高網站的性能(EntLib Caching)

第五步、介紹EntLib.Validation模塊信息、驗證器的實現層級及內置的各種驗證器的使用方法——上篇

第五步、介紹EntLib.Validation模塊信息、驗證器的實現層級及內置的各種驗證器的使用方法——中篇

第五步、介紹EntLib.Validation模塊信息、驗證器的實現層級及內置的各種驗證器的使用方法——下篇

第六步、使用Validation模塊進行服務器端數據驗證

第七步、Cryptographer加密模塊簡單分析、自定義加密接口及使用—上篇

第七步、Cryptographer加密模塊簡單分析、自定義加密接口及使用—下篇

第八步、使用Configuration Setting模塊等多種方式分類管理企業庫配置信息

第九步、使用PolicyInjection模塊進行AOP—PART1——基本使用介紹

第九步、使用PolicyInjection模塊進行AOP—PART2——自定義Matching Rule

第九步、使用PolicyInjection模塊進行AOP—PART3——內置Call Handler介紹

第九步、使用PolicyInjection模塊進行AOP—PART4——建立自定義Call Handler實現用戶操作日誌記錄

第十步、使用Unity解耦你的系統—PART1——爲什麼要使用Unity?

第十步、使用Unity解耦你的系統—PART2——瞭解Unity的使用方法(1)

第十步、使用Unity解耦你的系統—PART2——瞭解Unity的使用方法(2)

第十步、使用Unity解耦你的系統—PART2——瞭解Unity的使用方法(3)

第十步、使用Unity解耦你的系統—PART3——依賴注入

第十步、使用Unity解耦你的系統—PART4——Unity&PIAB

擴展學習:

擴展學習篇、庫中的依賴關係注入(重構 Microsoft Enterprise Library)[轉]

作者:kyo-yo
出處:http://kyo-yo.cnblogs.com
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章