Unity 容器:注册和解析
在上一节中,我们在控制台项目中安装了 Unity 框架。在这里,我们将学习如何使用 Unity 容器注册类型映射并解析它。
正如我们在 IoC 容器章节中学到的,每个容器都必须提供注册和解析依赖项的方法。Unity 容器为此提供了 RegisterType()
和 Resolve()
方法。
我们将在本章中使用以下示例类来演示依赖项的注册和解析。
public interface ICar
{
int Run();
}
public class BMW : ICar
{
private int _miles = 0;
public int Run()
{
return ++_miles;
}
}
public class Ford : ICar
{
private int _miles = 0;
public int Run()
{
return ++_miles;
}
}
public class Audi : ICar
{
private int _miles = 0;
public int Run()
{
return ++_miles;
}
}
public class Driver
{
private ICar _car = null;
public Driver(ICar car)
{
_car = car;
}
public void RunCar()
{
Console.WriteLine("Running {0} - {1} mile ", _car.GetType().Name, _car.Run());
}
}
正如你在示例类中看到的,Driver
类依赖于 ICar
接口。因此,当我们实例化 Driver
类对象时,我们将不得不传入一个实现 ICar
接口的类的实例,例如 BMW
、Audi
或 Ford
类,如下所示。
Driver driver = new Driver(new BMW());
driver.RunCar();
在上面的示例中,我们在创建 Driver
类对象时创建并传入了一个 BMW
对象。因此,我们手动注入了 Driver
类的依赖项。现在,我们将使用 Unity 容器来了解注册和解析依赖项的不同方式。
使用 UnityContainer
为了使用 Unity 容器,我们首先需要创建它的一个对象。你可以使用任何实现 IUnityContainer
接口的类。Unity 容器在 Microsoft.Practices.Unity
命名空间中包含了实现 IUnityContainer
接口的 UnityContainer
类。如果你需要扩展容器,那么你可以创建自己的自定义类并根据需要实现 IUnityContainer
接口。
using Microsoft.Practices.Unity;
IUnityContainer container = new UnityContainer();
//or
var container = new UnityContainer();
接下来,我们需要注册类型映射。
注册
在 Unity 解析依赖项之前,我们需要向容器注册类型映射,以便它能为给定类型创建正确的对象。使用 RegisterType()
方法注册类型映射。基本上,它配置了为哪个接口或基类实例化哪个类。例如,如果我们希望 Unity 容器在需要提供 ICar
接口的依赖项时创建并提供一个 BMW
类的对象,那么我们首先需要按照如下所示注册它。
IUnityContainer container = new UnityContainer();
container.RegisterType<ICar, BMW>();
这里,container.RegisterType<ICar, BMW>()
请求 Unity 在需要注入 ICar
对象时,创建一个 BMW
类的对象并通过构造函数注入它。
RegisterType 方法包含许多重载。在 MSDN 上了解 RegisterType 的所有重载。
所以现在,注册之后,我们可以使用 Resolve()
方法。
解析
Unity 使用 resolve()
方法创建指定类的对象并自动注入依赖项。我们上面将 BMW
注册到 ICar
。现在,我们可以使用 Unity 容器实例化 Driver
类,而无需使用 new
关键字,如下所示。
IUnityContainer container = new UnityContainer();
container.RegisterType<ICar, BMW>();// Map ICar with BMW
//Resolves dependencies and returns the Driver object
Driver drv = container.Resolve<Driver>();
drv.RunCar();
在上面的示例中,Unity 容器使用 container.Resolve<Driver>()
方法创建了 Driver
类的一个对象。Driver
类是 ICar
的依赖项。因此,container.Resolve<Driver>()
通过自动创建并注入一个 BMW
对象来返回 Driver
类的一个对象。所有这些都在幕后进行。BMW
对象被创建并注入,因为我们将 BMW
类型注册到了 ICar
。
每次我们解析相同的类型时,Unity 容器都会创建一个新对象并注入它。
var container = new UnityContainer();
container.RegisterType<ICar, BMW>();
Driver driver1 = container.Resolve<Driver>();
driver1.RunCar();
Driver driver2 = container.Resolve<Driver>();
driver2.RunCar();
行驶中的宝马 - 1 英里
在上面的示例中,每当容器解析 Driver
类时,它都会注入 BMW
对象,例如 driver1 和 driver2 都引用了单独的 BMW
对象。
因此,你可以使用 Unity 容器创建指定类型的对象。在 MSDN 上了解 Resolve 方法的所有重载。
多次注册
如果你注册了相同类型的多个映射,Unity 容器将注入最后注册的类型。
IUnityContainer container = new UnityContainer();
container.RegisterType<ICar, BMW>();
container.RegisterType<ICar, Audi>();
Driver driver = container.Resolve<Driver>();
driver.RunCar();
在上面的示例中,ICar
映射到 BMW
和 Audi
。然而,Unity 将每次注入 Audi
,因为它最后注册。
注册命名类型
你可以注册一个带有名称的类型映射,然后你可以在 Resolve()
方法中使用该名称。
IUnityContainer container = new UnityContainer();
container.RegisterType<ICar, BMW>();
container.RegisterType<ICar, Audi>("LuxuryCar");
ICar bmw = container.Resolve<ICar>(); // returns the BMW object
ICar audi = container.Resolve<ICar>("LuxuryCar"); // returns the Audi object
如上所示,我们已经将 ICar
映射到 BMW
和 Audi
类。然而,我们为 ICar-Audi 映射指定了名称 "LuxuryCar"。所以现在,如果我们指定映射名称,Resolve()
方法将返回一个 Audi 对象。
考虑以下示例
var container = new UnityContainer();
container.RegisterType<ICar, BMW>();
container.RegisterType<ICar, Audi>("LuxuryCar");
// Registers Driver type
container.RegisterType<Driver>("LuxuryCarDriver",
new InjectionConstructor(container.Resolve<ICar>("LuxuryCar")));
Driver driver1 = container.Resolve<Driver>();// injects BMW
driver1.RunCar();
Driver driver2 = container.Resolve<Driver>("LuxuryCarDriver");// injects Audi
driver2.RunCar();
奥迪行驶中 - 1 英里
在上面的例子中,我们用名称 "LuxuryCarDriver" 注册了 Driver
类,并指定了一个 InjectionConstructor
对象。new InjectionConstructor(container.Resolve<ICar>("LuxuryCar"))
为 Driver
类指定了一个构造函数注入,它传递了一个 Audi
对象,因为 container.Resolve<ICar>("LuxuryCar")
返回一个 Audi
对象。所以现在,我们可以使用 container.Resolve<Driver>("LuxuryCarDriver")
来解析带有 Audi
的 Driver
,即使 ICar
默认注册为 BMW
。
注册实例
Unity 容器允许我们使用 RegisterInstance()
方法注册现有实例。它不会为注册类型创建新实例,我们每次都将使用相同的实例。
var container = new UnityContainer();
ICar audi = new Audi();
container.RegisterInstance<ICar>(audi);
Driver driver1 = container.Resolve<Driver>();
driver1.RunCar();
driver1.RunCar();
Driver driver2 = container.Resolve<Driver>();
driver2.RunCar();
奥迪行驶中 - 2 英里
奥迪行驶中 - 3 英里
因此,我们可以使用 Unity 容器注册和解析不同类型。在下一章中了解 Unity 容器如何执行构造函数注入。