Unity 是由微軟開發的一個輕量級、可擴展的依賴注入(Dependency Injection, DI)容器,支持構造函數、屬性和方法的依賴注入。所謂依賴的注入,即將程序開發過程中的對象與其所依賴的具體對象解耦,從一定程度上僅關注對所依賴對象的使用,卻不管其具體對象是哪個類的實例;而真正的被依賴對象在運行時由容器注入。本質上,它就是一個對象工廠和對象管理器。更詳細的信息,請參見《IoC 容器和Dependency Injection 模式》。
Unity 適用於可擴展、可插接的應用程序的開發,對於普通的、不要求插接的應用程序的開發反而會增加開發的復雜度。Unity 的使用對性能也會有少量的影響 。
准備
在本系列的文章中,我們假設有一個 Telephone 類,一個 IDialer 接口和一個 Dialer 抽象類。如下代碼所示:
Unity 的初始化
Unity 容器在使用前一般需要針對所使用的對象類型進行初始化,某些時候也可以不進行初始化。Unity 容器的初始化主要是對象類型的注冊。這可以用二種方法完成,一是使用 .NET 代碼,另一種就是使用 XML 配置文件。在 Unity 文檔的示例中,絕大多數的示例都是使用代碼的方法來對 Untiy 進行初始化,這也給不少人造成了使用 Unity 容器來管理對象比直接使用更復雜的錯覺。本文將同時使用代碼和 XML 配置文件的方法來對初始化及其其他相關方面進行說明,以便大家對 Unity 能有更全面、更正確的認識。
類型注冊
首先,在代碼文件中添加對 Microsoft.Practices.Unity 命名空間的引用。
然後,可以用代碼方式進行如下的注冊,(其中的 ButtonTypeDialer 類包含在供下載的源代碼中。):
運行結果如下:
下面,我們看看用 XML 如何來進行初始化。
首先,在配置文件中,需要添加下列配置節聲明:
然後,配置類型注冊:
最後,我們可以用下列的方式來使用:
由上面的代碼我們可以看出,在完成 Unity 的容器初始化後,使用的方法是一樣的。
構造函數注入
實質上,上面的示例我們可以用如下代碼來實現:
這二段代碼唯一的不同就是 38、39 行合並成了 52 這一行。這就是利用了構造函數注入。
在 Telephone 類中,我們聲明了一個 public Telephone(IDialer dialer) 的構造函數,而在 Unity 容器中,已進行了用於 IDialer 接口的注冊,所以在使用 Unity 容器的 Resolve 方法獲取對象時,就自動調用了此構造函數對對象進行了初始化。如果不存在這樣的構造函數,Unity 容器將自動調用其默認構造函數進行初始化。
如果同時存在多個帶參數的構造函數,就需要用 [InjectionConstructor] 特性來指定將使用的構造函數。
屬性注入
要使用屬性注入,我們需要在 Telephone 類的 Dialer 屬性上加上 [Dependency] 特性聲明,如下所示:
同時,在配置文件中加入如下配置以注冊 Dialer 抽象類的映射:
這樣,構造函數注入中的示例代碼就依然是有效的,雖然構造函數已被注釋掉了。
方法調用注入
我們對 Telephone 類做進一步的修改,注釋掉 [Dependency] 特性,添加一個 Initialize 方法:
在 Initialize 方法上,我們加上了 [InjectionMethod] 以指出使用了方法調用注入的方法。這也使得在構造函數注入中所使用的示例代碼依然有效。
總結
Unity 是一個輕量級、可擴展的 DI 容器,它可以用代碼或配置文件來進行類型的注冊,同時支持構造函數注入、屬性注入和方法調用注入。
本文配套源碼