Unity是微軟Patterns & Practices團隊所開發的一個輕量級的,而且可擴展的依賴注入(Dependency Injection)容器,它支持經常使用的三種依賴注入方式:構造器注入(Constructor Injection)、屬性注入(Property Injection),以及方法調用注入(Method Call Injection).如今Unity最新的版本的1.2版,能夠在微軟的開源站點http://unity.codeplex.com下載最新的發佈版本和文檔。經過使用Unity,咱們能輕鬆構建鬆耦合結構的程序,從而讓整個程序框架變得清晰和易於維護。編程
在日常的軟件編碼過程當中,程序的邏輯每每很複雜,尤爲是大型項目的開發中,一個模塊經常會去引用其餘的模塊,假設咱們有一個監控器類,用來監控CPU的溫度,當溫度達到預警的範圍時,監控器有一個報警的方法,方法裏面經過短信提醒器,以發送短信的方式通知維護人員。因而就出現了下面這樣一段最爲常見的代碼:框架
1: public class Monitor
2: {
3: public void Alarm()
4: {
5: SMSNotify notify = new SMSNotify();
6: notify.Send();
7: }
8: }
在Monitor類中,直接引用到了一個短信提醒器的類,這是最爲不靈活和最不易於擴展的一種方式。或許咱們想到了面向接口編程,利用多態的好處,能夠提供靈活的不一樣子類的實現,增長代碼擴展性等等。可是說到底,接口必定是須要實現的,也就是以下語句早晚要執行:函數
1: public void Alarm()
2: {
3: INotify notify = new SMSNotify();
4: notify.Send();
5: }
這樣看來,在實現INotify這個接口的時候,仍然須要具體的類來實現,而這樣的代碼在程序編譯的時候就已經固定下來,若是之後須要使用新的提醒器,仍舊須要修改源代碼並從新編譯。而且在咱們的Monitor類中,明顯依賴SMSNotify類,兩者之間的耦合度很是緊密。所以Ioc(控制反轉)模式被提出用來解決這種問題,也即把接口的具體實現延緩到運行時,接口的實現類是在運行時被裝載的。這樣,就算有了新的實現類,也不須要更改調用者的代碼(能夠在Unity中使用配置文件的方式實現)。這種Ioc模式能夠被形象的比喻爲:接口就像一個空殼,而在具體實現時,向這個空殼注入內容,而讓它成爲一個真正的實體。這種模式也被形象的稱爲:依賴注入。經過使用Unity,咱們能構建鬆耦合的軟件,而且對象之間相互關聯的細節,咱們也沒必要關心,能夠交由依賴注入容器全權負責。編碼
前面也提到了依賴注入經常使用的三種形式:構造器注入、屬性注入和方法調用注入,咱們能夠經過例子來實現這三種形式的注入。仍是以上面的場景爲例:spa
1.Constructor Injectioncode
IMonitor接口定義:對象
1: public interface IMonitor
2: {
3: void Alarm();
4: }
Monitor類:接口
1: public class Monitor : IMonitor
2: {
3: private INotify notify;
4:
5: public Monitor(INotify n)
6: {
7: notify = n;
8: }
9:
10: public void Alarm()
11: {
12: notify.Send();
13: }
14: }
INotify接口定義:開發
1: public interface INotify
2: {
3: void Send();
4: }
EmailNotify類:文檔
1: public class EmailNotify : INotify
2: {
3: public void Send()
4: {
5: Console.WriteLine("Send Email Notify...");
6: }
7: }
SMSNotify類:
1: public class SMSNotify : INotify
2: {
3: public void Send()
4: {
5: Console.WriteLine("Send SMS Notify...");
6: }
7: }
能夠看到,在Monitor類的構造函數裏面,傳入的參數是一個INotify接口類型,Alarm方法,調用了實現類的Send方法,但具體調用哪個實現類的Send方法,只有在注入實體後才知道。Unity容器中,一般使用RegisterType和Resolve方法來分別註冊和獲取實例,而且這兩個方法有不少泛型和非泛型的重載,具體的類型和參數,能夠參考Unity的官方幫助文檔。
如今咱們向Monitor的構造函數注入實現INotify接口的實例:
1: static void Main(string[] args)
2: {
3: IUnityContainer container = new UnityContainer();
4: container.RegisterType<IMonitor, Monitor>().RegisterType<INotify, SMSNotify>();
5:
6: IMonitor monitor = container.Resolve<IMonitor>();
7: monitor.Alarm();
8:
9: Console.ReadLine();
10: }
代碼中咱們注入的INotify實例是SMSNotify類的實例,而後調用monitor.Alrarm(),裏面會調用notify.Send().
上面是針對單個構造函數的狀況,若是有多個構造函數,須要指明哪一個構造函數是須要被注入的,也即須要在指定被注入的構造函數加上attribute:InjectionConstructor
1: public Monitor(INotify n, string name)
2: {
3: notify = n;
4: }
5:
6: [InjectionConstructor]
7: public Monitor(INotify n)
8: {
9: notify = n;
10: }
運行後可獲得同樣的結果.
2.Property Injection
經過屬性注入,咱們須要加上attribute: Dependency,使得Unity容器在獲取類對象實例時,自動實例化該屬性所依賴的對象,並注入到屬性中。
修改Monitor類,實現下面的代碼:
1: public class Monitor : IMonitor
2: {
3: [Dependency]
4: public INotify Notify { get; set; }
5:
6: public void Alarm()
7: {
8: Notify.Send();
9: }
10: }
再在Main函數裏面,修改原有的代碼,此次咱們讓容器注入EmailNotify實例:
1: container.RegisterType<INotify, EmailNotify>();
還有一個比較方便的地方,能夠爲Dependency特性指定名稱,這樣,在注入時,會將RegisterType所指定的對應名稱的實體進行注入,例如:
1: public class Monitor : IMonitor
2: {
3: [Dependency("SMS")]
4: public INotify Notify { get; set; }
5:
6: public void Alarm()
7: {
8: Notify.Send();
9: }
10: }
修改Main函數,在RegisterType函數中指定注入名稱:
1: container.RegisterType<INotify, EmailNotify>("Email");
2: container.RegisterType<INotify, SMSNotify>("SMS");
3.Method Call Injection
Method Call Injection注入的時機和Constructor Injection有必定的區別,構造函數注入,是在容器建立實例的時候,而方法調用注入,是在方法被調用的時候。實現方法調用注入,須要在指定注入的方法前加上attribute: InjectionMethod
修改Monitor類的代碼以下:
1: public class Monitor : IMonitor
2: {
3: private INotify notify;
4:
5: [InjectionMethod]
6: public void GetNotify(INotify n)
7: {
8: notify = n;
9: }
10:
11: public void Alarm()
12: {
13: notify.Send();
14: }
15: }
在程序運行時,容器會自動實例化GetNotify方法所依賴的對象,並自動調用該方法,將其注入到方法中。
Main函數以下:
1: static void Main(string[] args)
2: {
3: IUnityContainer container = new UnityContainer();
4: container.RegisterType<IMonitor, Monitor>();
5: container.RegisterType<INotify, EmailNotify>();
6:
7: IMonitor monitor = container.Resolve<IMonitor>();
8: monitor.Alarm();
9:
10: Console.ReadLine();
11: }
摘自(http://www.lywill.com/archives/kf/2013/Microsoft-Practices-UnityRuMen/)