目錄
介紹
這是我關於依賴反轉原理和依賴注入的文章的第五部分也是最後一部分。在上一部分中,我實現了一個自定義容器,其功能非常有限,可用於註冊依賴項並在需要依賴項實例時進行解析。現在,有很多工具可以用來實現依賴注入,例如UnityContainer,StructureMap,Windsor Castle,NInject等等。在這一部分中,我將解釋所提供的不同功能UnitContainer以及如何註冊依賴項以及如何解決已註冊的依賴項。
如果您是該部分的直接訪問者,可能會很難理解代碼。因此,在開始閱讀本文之前,請仔細閱讀前面的部分。爲了方便地瀏覽以前的文章,我提供了以下鏈接:
- 第1部分:依賴倒置原則
- 第2部分:控制反轉和IoC容器
- 第3部分:自定義IoC容器
- 第4部分:具有生命週期選項的自定義IoC容器
- 第5部分:使用Microsoft Unity的依賴注入(DI)(當前正在閱讀)
總覽
Unity容器(Unity)是功能齊全的可擴展依賴項注入容器。它有助於構建松耦合應用程序,併爲開發人員提供以下優勢:
- 簡化的對象創建,尤其是對於分層對象結構和依賴項
- 需求抽象;這使開發人員可以在運行時或配置中指定依賴項,並簡化橫切關注點的管理
- 通過將組件配置推遲到容器來提高靈活性
- 服務定位能力;這允許客戶端存儲或緩存容器
- 實例和類型攔截
- 約定註冊
通過[https://github.com/unitycontainer/unity]
依賴註冊
註冊一個依賴項可使IoC容器知道依賴項的具體實現。例如,如果要在請求解析IReader依賴項時獲取KeyboardReader實例,則需要註冊IReader解析KeyboardReader類實例的依賴項。以下是使用Unity容器進行依賴項註冊的示例。
IUnityContainer container = new UnityContainer();
container.RegisterType<IReader, KeyboardReader>();
通過上述註冊,解析類型IReader[container.Resolve<IReader>()]時,將返回一個KeyboardReader實例。
UnityContainer通過以下方式支持依賴項註冊。
實例註冊
通過執行實例註冊,我們告訴IoC容器,當有人請求解決依賴性時,將返回註冊的實例。在要以特定狀態註冊依賴項的情況下,實例註冊非常有用。該RegisterInstance()方法用於在容器中註冊實例。
var keyboardReader = new KeyboardReader();
container.RegisterInstance(keyboardReader);
通過上述註冊,解析類型KeyboardReader[ container.Resolve<KeyboardReader>()]時,將返回註冊的實例。
實例可以使用名稱在IoC容器中註冊。示例如下:
var keyboardReaderA = new KeyboardReader();
var keyboardReaderB = new KeyboardReader();
container.RegisterInstance("InstanceA", keyboardReaderA);
container.RegisterInstance("InstanceB", keyboardReaderB);
使用上述註冊,在解析類型KeyboardReader時,我們需要提供名稱,因爲沒有註冊就沒有名稱。因此,在上述情況下,使用container.Resolve(KeyboardReader, "InstanceA")解析類型KeyboardReader將返回keyboarderReaderA實例,而使用container.Resolve(KeyboardReader, "InstanceB")解析類型KeyboardReader將返回keyboardReaderB。
實例註冊還支持類型映射。這意味着可以針對類型(類或接口)註冊實例,以便在解析該類型時,已註冊的實例將返回給調用方。示例如下:
var keyboardReader = new KeyboardReader();
container.RegisterInstance<IReader>(keyboardReader);
通過上述註冊,解析類型KeyboardReader[ container.Resolve<IReader>()]時,將返回註冊的keyboardReader實例。
工廠註冊
使用工廠註冊,我們可以基於函數調用的輸出來註冊依賴項。在註冊實例時,它提供了更多控制權。
var keyboardReader = new KeyboardReader();
container.RegisterFactory<IReader>(fn => new KeyboardReader());
類型註冊
類型註冊是廣泛使用的註冊。在這種類型的註冊中,我們需要提供鍥約類型和具體類型,其中解析鍥約類型將產生具體類型的實例。類型註冊的最低要求是類型本身。以下是註冊示例:
container.RegisterType<KeyboardReader>();
通過上述註冊,解析類型KeyboardReader[ container.Resolve<KeyboardReader>()]時,將返回KeyboardReader的實例。
以下是註冊的另一個示例,我們可以提供鍥約類型及其具體類型。
container.RegisterType<IReader, KeyboardReader>(); // default registration
通過上述註冊,解析類型KeyboardReader[ container.Resolve<IReader>()]時,將返回KeyboardReader的實例。
我們還可以在註冊類型時提供名稱:
container.RegisterType<IReader, KeyboardReader>("Keyboard");
通過上面的註冊來解決依賴關係,我們需要使用container.Resolve<IReader>("Keyboard")。
注意:名稱的默認值爲null。當我們註冊一個類型而不傳遞任何名稱時,這種註冊稱爲default registration。
樣例應用程序
讓我們使用Visual Studio創建一個控制檯應用程序。在此演示應用程序中,我使用了Visual Studio 2019。但是您可以使用任何版本的Visual Studio(Visual Studio 2012及更高版本)。
右鍵單擊該項目,然後單擊“管理NuGet軟件包... ”。管理NuGet包用於將3個第三方庫添加的應用程序。
在“管理NuGet軟件包”窗口中,選擇“瀏覽”選項,然後搜索Unity並安裝該軟件包。在撰寫本文時,Unity的最新版本爲5.11.6。但是您可以將任何穩定版用於演示應用程序。
在Program.cs文件中添加以下代碼行:
using System;
using Unity;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IReader, KeyboardRader>();
var reader = container.Resolve<IReader>();
var readText = reader.Read();
Console.WriteLine($"The output is : {readText}");
Console.ReadLine();
}
}
interface IReader
{
string Read();
}
class KeyboardRader : IReader
{
public string Read()
{
return "Reading from keyboard...";
}
}
}
您的示例應用程序已準備好運行。按F5鍵運行控制檯應用程序。
您將獲得以下輸出:
如您所見,我們已經使用Typed註冊爲KeyboardReader具體類型註冊了IReader類型。因此,當我們嘗試解析類型IReader時,我們將獲得KeyboardReader的實例。並調用Read()方法將返回“Reading from keyboard ... ”,該信息已打印在控制檯上。
總結
在本文的這一部分中,我解釋了什麼是UnityContainer,如何註冊依賴關係,並創建了一個演示應用程序以顯示使用UnityContainer註冊和解決依賴關係。