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

認識IoC

編輯:C#入門知識

  第一次接觸IoC是我在學習MVP框架的時候,搭建一個MVP框架需要用到IoC,那時候就以為IoC就是依賴注入,但在後來的逐步了解中發現那個只是它的別名而已。IoC全稱應該是Inversion of Control,中文稱為控制反轉;而依賴注入的簡稱是DI,全稱是Dependency Injection,個人覺得這兩者也不是那麼一個別名的關系而已,控制反轉給我的感覺更多的是一種思想,而依賴注入卻正好是一種實現方式。那這裡說說概念

  •  控制反轉:應用本身不負責以來對象的維護和創建,而交給一個外部容器來負責。這樣控制權就由應用轉到了外部IoC容器,控制權就實現了所謂的反轉。
  •  依賴注入:由外部容器在運行時動態地將以來的對象注入到組件中。

以上概念摘自蔣老師的著作《ASP.NET MVC4 框架揭秘》。但是技術這東西又沒必要向理論學術那樣嚴謹,能讓人知曉其中意圖則可,最初UML最初創作處理也是為了達到這個目的。

 

  高內聚低耦合一直是軟件開發中不斷追求的,現在各種框架MVC,MVP等都是為了解耦而誕生的。在我閱讀微軟的開源項目PetShop時發現裡面用了耳熟能詳的三層架構中使用了最初我學C#時不知有什麼作用的一個東西——接口Interface。它的存在很大的目的就是為了解耦,它能使一些比較具體的事物抽象化。那麼本篇所討論的IoC也是使用了接口。

目前有很多IoC框架:Unity,Spring.NeT,Ninject,StructureMap等。Ninject在我實踐MVP的時候用過,Unity在我閱讀蔣老師的著作時了解過,那麼這回我將會嘗試一下之前沒用過的Unity,體驗一下依賴注入。

         模擬使用一個三層架構來體驗這個Unity

         定義DAL,BLL,UI層的接口IDAL,IBLL,IUI以及實現它們的類DAL,BLL,UI。

 1     interface IDAL
 2     {
 3         DataTable QueryDatas();
 4     }
 5     interface IBLL
 6     {
 7         List<object> GetSomeDatas();
 8     }
 9 
10     interface IUI
11     {
12         void ShowData(IBLL bll);
13     }
14 
15     class DAL : IDAL
16     {
17 
18         public DataTable QueryDatas()
19         {
20             DataTable table = new DataTable();
21             table.Columns.Add("Col");
22             for (int i = 0; i < 10; i++)
23             {
24                 table.Rows.Add(i);
25             }
26             return table;
27         }
28     }
29     class BLL : IBLL
30     {
31         [Dependency]
32         public IDAL dal { get; set; }
33 
34         public List<object> GetSomeDatas()
35         {
36             List<object> result = new List<object>();
37             DataTable table = dal.QueryDatas();
38             foreach (DataRow row in table.Rows)
39             {
40                 result.Add(row[0]);
41             }
42             return result;
43         }
44     }
45     class UI : IUI
46     {
47         [InjectionMethod]
48         public void ShowData(IBLL bll)
49         {
50             List<object> datas = bll.GetSomeDatas();
51             foreach (object item in datas)
52             {
53                 Console.WriteLine(item);
54             }
55         }
56     }

在上面的代碼中BLL類的dal屬性使用了[Dependency] Attribute,使得該屬性是通過IoC容器自動去賦值,不需要通過代碼給它顯示賦值。UI的ShowData方法用了[InjectionMethod] Attribute,該方法在UI類被IoC容器自動執行。實際上上面代碼設計到IoC裡面三種方式的其中兩種屬性注入和接口(方法)注入,那麼還剩下一種就是構造器注入,

  • 在上面使用了Dependency  Attribute的IDAL屬性則是使用屬性注入,使用了依賴注入的屬性在IoC容器構造對象的時候自動初始化賦值;
  • 上面使用了InjectionMethod Attribute的ShowData方法則是使用接口(方法)注入,使用了依賴注入的方法在IoC容器構造對象的時候自動執行該方法;
  • 還有一種沒有列舉出來的就是構造器注入, IoC容器會自動選擇和調用合適的構造函數以創建依賴的對象。如果被選擇的構造函數是帶參數的,IoC容器是會去創建該參數的實例的。上面的代碼還沒可以執行,需要在配置文件中添加以下內容
 1 <configuration>
 2   <configSections>
 3     <section name="unity"
 4              type="
 5              Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
 6              Microsoft.Practices.Unity.Configuration"/>
 7   </configSections>
 8   <unity>
 9     <containers>
10       <container name="defaultContainer">
11         <register type="AllTypeTestControl.IDAL,AllTypeTestControl" mapTo="AllTypeTestControl.DAL,AllTypeTestControl"/>
12         <register type="AllTypeTestControl.IBLL,AllTypeTestControl" mapTo="AllTypeTestControl.BLL,AllTypeTestControl"/>
13         <register type="AllTypeTestControl.IUI,AllTypeTestControl" mapTo="AllTypeTestControl.UI,AllTypeTestControl"/>
14       </container>
15     </containers>
16   </unity>
17 </configuration>

上面這段內容是指定了給Unity的IoC容器各個接口與實現類的映射關系,AllTypeTestControl.IDAL類型映射到AllTypeTestControl.DAL中去,表示通過DAL來實現IDAL的注入,其他同理。但每一項的注冊要按照

<register type="接口全名,程序集名" mapTo="類全名,程序集名"/> 

通過下面的測試代碼來測試

1         public static void TestMain()
2         {
3             IUnityContainer container = new UnityContainer();
4             UnityConfigurationSection configuration = 
5                 ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) 
6                 as UnityConfigurationSection;
7             configuration.Configure(container, "defaultContainer");
8             UI ui = container.Resolve<IUI>() as UI ;
9         }

主要是構造了一個IoC的容器,然後載入了配置文件的映射信息,除了通過配置文件來確定映射關系外,還可以通過代碼的形式來確定

        public static void TestMain()
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IDAL, DAL>();
            container.RegisterType<IBLL, BLL>();
            container.RegisterType<IUI, UI>();
            UI ui = container.Resolve<IUI>() as UI ;
        }

代碼的運行結果如下

現在則把上面的BLL作一下修改

 1     class BLL : IBLL
 2     {
 3         //[Dependency]
 4         //public IDAL dal { get; set; }
 5 
 6         private IDAL dal;
 7 
 8         //[InjectionConstructor]
 9         public BLL(IDAL dal)
10         {
11             this.dal = dal;
12         }
13 
14         //[InjectionConstructor]
15         public BLL()
16         { 
17         
18         }
19 
20         public List<object> GetSomeDatas()
21         {
22             List<object> result = new List<object>();
23             DataTable table = dal.QueryDatas();
24             foreach (DataRow row in table.Rows)
25             {
26                 result.Add(row[0]);
27             }
28             return result;
29         }
30     }

結果仍然和上面的一樣,IoC容器仍然能正確的匹配出類型構造了DAL對象。那麼如果給BLL()構造函數加了InjectionConstructor Attribute,IoC容器只會去匹對帶了InjectionConstructor Attribute的構造函數,這樣BLL(IDAL dal)構造函數則不會被調用,運行起來就會拋出空引用異常。假如給BLL(IDAL dal)也加上了InjectionConstructor Attribute,那麼它與無參構造函數BLL()屬於同級,IoC則會也調用BLL(IDAL dal)構造函數,dal字段能被正常的賦值。

  通過上面的實踐中能感覺到IoC有GOF中的工廠模式思想。用戶在使用著一個對象,但它並不負責對象的構造,把對象的構造移交了給第三方,在IoC中就是IoC容器,在工廠方法裡面則是工廠了。在ASP.NET MVC中也使用了IoC,迷你MVC框架中控制器的構造是通過了一個工廠利用反射機制來構造出來的,而實際的ASP.NET MVC則是使用了IoC。

  對IoC的了解還不算多,手上有一份Ninject的源碼,但一直沒看,現在工作忙了,連博客也少寫了,時間得好好分配,要保持學習。以上有什麼說的不對的請指正,有什麼好的建議或意見也請分享,謝謝!

 

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