IOC詳解和Unity基礎使用介紹


說起IOC,可能很多初學者不知道是用來做什么的,今天正好有點時間,就來掃掃盲,順便鞏固下自己。

IOC全稱是Inversion Of Control,意為控制反轉(這些自然百度也有),可什么是控制反轉呢?

按我現在的理解,把上端依賴的項從細節轉換為抽象,並把細節轉移到第三方,這個就叫控制反轉。

怎么理解呢?最簡單的:我們有一個接口Ianimal,就像這樣:

1
2
3
4
public  interface iAnimal
     {
         void  talk();
     }

然后我們現在用另一個類去實現該接口:

1
2
3
4
5
6
7
public  class dog : iAnimal
     {
         public  void talk()
         {
             Console.Write( "小狗說:汪汪汪!" );
         }
     }

然后呢,往常來講,我們應該是這樣調用的:

1
2
3
iAnimal dog =  new  dog();
dog.talk();
Console.ReadKey();

運行結果應該是這樣的:

到目前為止都是正確的,相信各位小伙伴一般也是如此。

但請注意,我們在調用時是直接用dog類型new出來的,這種做法其實就已經依賴於細節了。

那么如何將這里依賴的細節修改為抽象呢?很簡單,我們只需要一個工廠類幫助我們生成實際的類即可。

但是有些小伙伴可能想,工廠內也有細節啊,難道寫個工廠就是IOC了么?

當然不是,我們還將細節交給配置文件(通過反射),這樣在功能變動時,無需修改原代碼,只需要修改配置文件即可。

工廠看上去是這樣的:

1
2
3
4
5
6
7
8
9
10
public  class SimpleFactory
     {
         public  static iAnimal CreateAnimal()
         {
             string  classModule = ConfigurationManager.AppSettings["PhoneType"];
             Assembly assembly = Assembly.Load(classModule.Split( ',' )[1]);
             Type type = assembly.GetType(classModule.Split( ',' )[0]);
             return  (iAnimal)Activator.CreateInstance(type);
         }
     }

而我們的配置文件自然也要寫點東西了:

1
2
3
<appSettings>
     <add key= "AnimalType"  value="IOCandDI.dog,IOCandDI"/>
</appSettings>

value內,逗號前是類的全限定名(命名空間+類名),后面是命名空間。

不會操作配置文件的小伙伴們,先添加這個引用:

然后引入System.Configuration命名空間就可以操作啦。

至於反射,直接引入System.Reflection 命名空間即可操作。反射的原理也很簡單,在這里就不再贅述。

修改過后的調用和以前的調用對比:

1
2
3
4
5
6
iAnimal dog =  new  dog();
dog.talk();
 
iAnimal obj = SimpleFactory.CreateAnimal();
obj.talk();
Console.ReadKey();

結果是一樣的:

這個時候,如果再多一種動物,只需要添加一個繼承iAnimal接口的類,並且修改配置文件即可。

IOC帶給我們的便利正是如此。

微軟也推出了一款IOC的插件,叫做Unity,你在NuGet程序包管理中很輕松就能找到它:

首先是下載與安裝:

然后在頁面引入Microsoft.Practices.Unity就可以操作了,基本流程如下:

1
2
3
4
IUnityContainer container =  new  UnityContainer();//聲明容器
container.RegisterType<iAnimal, cat>(); //注冊類型
iAnimal obj = container.Resolve<cat>(); //完成實例
obj.talk();

運行效果:

了解了Unity的基礎用法,我們在來看下如何利用Unity做依賴注入(DI——dependency injection)。

說到DI,就一定要知道DI的三種方式:屬性注入、構造注入、方法注入。我這里直接改造了cat類:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public  class cat : iAnimal
    {
        [Dependency]
        public  iColor color { get; set; }
        public  iEat eat { get; set; }
        public  iRun run { get; set; }
 
        [InjectionConstructor]
        public  cat(iEat ieat)
        {
            eat = ieat;
        }
 
        public  void talk()
        {
            Console.WriteLine( "小貓說:喵喵喵!" );
        }
 
        [InjectionMethod]
        public  void Happy(iRun irun)
        {
            run = irun;
        }
    }

大家一定發現了我分別在屬性、構造、方法頭上加了特性。

實際上,Dependency、InjectionConstructor、InjectionMethod就是Unity中DI操作的標識符,它們分別對應屬性注入、構造注入、方法注入。

那么,這些特性是如何幫助程序完成DI的呢?看調用代碼:

1
2
3
4
5
6
7
8
9
10
11
12
IUnityContainer container =  new  UnityContainer();
container.RegisterType<iAnimal, cat>();
container.RegisterType<iColor, Color>();
container.RegisterType<iEat, Eat>();
container.RegisterType<iRun, Run>();
iAnimal obj = container.Resolve<cat>();
obj.talk();
cat myCat = (cat)obj;
Console.WriteLine( "myCat.color是空的么?{0}" , myCat.color ==  null );
Console.WriteLine( "myCat.eat是空的么?{0}" , myCat.eat ==  null );
Console.WriteLine( "myCat.run是空的么?{0}" , myCat.run ==  null );
Console.ReadKey();

在Unity容器內類型注冊時,需注冊cat類內3個參數的類型,用來對應3種注入方式。

運行結果如下:

3種注入方式都成功了~添加了特性的屬性(或方法)在Unity容器執行實例時會自動尋找上面3個特性(的位置)並匹配注冊類型(完成注入)。

需要注意的是,構造注入無需聲明特性也可生效,Unity會自動尋找參數最多的構造參數進行注入(前提是被注入的參數類型一定要注冊)。

ADD:在和一位小伙伴討論時,他指出了我unity的使用方法有問題,我這里的確沒有將unity容器的細節抽出到配置文件中(因為想着是基礎使用教程就沒有加),這一方面我也懶得再寫,找到一篇介紹詳細的博文供大家參考——http://www.cnblogs.com/junchu25/archive/2012/08/10/2631455.html


免責聲明!

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



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