在软件开发中,控制反转(IoC)是一种设计原则,旨在减少软件组件之间的耦合度。依赖注入(DI)是实现IoC的一种方式,它通过在运行时注入类的依赖项来实现。这样做的好处是,当一个类发生变化时,不会影响依赖它的其他类,从而实现了类之间的松耦合。
为了自动注入依赖项,通常会使用依赖注入(DI)容器。虽然也可以手动注入依赖项,但使用DI容器有以下好处:
以下示例将展示如何使用Unity来管理依赖项。Unity具有简单的API,并且易于配置。
假设有一个Employee类,它需要IDBAccess作为构造函数依赖项。为了使用依赖注入创建松耦合架构,使用接口来消除类之间的直接依赖关系。
public class Employee
{
public string Name { get; set; }
private IDBAccess _DBAccess;
public Employee(IDBAccess DBAccess)
{
_DBAccess = DBAccess;
}
}
要使用Unity DI容器实现依赖注入,需要添加Unity的Nuget包,这将为项目添加所需的引用。
添加上述Nuget包后,会向项目添加以下引用:
这些主要程序集实现了依赖注入功能。
向容器注册对象,并从容器中检索对象,因此客户端直接与容器交互。
在应用程序中使用Unity DI容器主要有两个步骤:
注册依赖项时,使用RegisterType方法。这是一个泛型方法,需要提供接口类型或抽象类与需要实例化的具现类型的映射。首先,实例化容器。
var container = new UnityContainer();
container.RegisterType();
上述依赖项添加了IDBAccess和SQLDataAccess类型之间的映射。这意味着每当需要IDBAccess类型的依赖项时,就会创建SQLDataAccess的实例,并注入到依赖类型中。
要创建一个依赖项的类,可以使用构造函数注入或属性注入。使用Resolve方法时,必要的依赖项会自动注入。因此,不需要自己提供依赖项。
Employee employee = container.Resolve();
调用Resolve()方法时,Employee类所需的依赖项会自动注入。由于Employee类依赖于IDBAccess接口,并且已经注册了IDBAccess接口和SQLDataAccess类之间的映射,容器会自动创建SQLDataAccess的实例,并将其传递给Employee类的构造函数。
要实现属性注入,需要在类的属性上应用[Dependency]属性。
public class Employee
{
private PersonalDetails personalDetails;
[Dependency]
public PersonalDetails PersonalDetails
{
get { return personalDetails; }
set { personalDetails = value; }
}
}
现在,当使用Unity容器创建Employee对象时,PersonalDetails对象会自动创建并分配给PersonalDetails属性。
虽然在代码中注册类型是更好的方法,因为它可以轻松捕获错误。但这也意味着需要重新编译代码。
另一种在Unity容器中注册类型的方法是使用配置文件。如果使用配置文件,那么可以轻松地更改注册信息而无需重新编译代码。
以下是一个示例XML配置文件,它在Unity容器中注册了依赖项。注册的类型与在代码中注册的类型相同。
<?xml version="1.0" encoding="utf-8"?>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
</configSections>
<typeAliases>
<typeAlias alias="IDBAccess" type="DIContainer.IDBAccess, DIContainer"/>
<typeAlias alias="SQLDataAccess" type="DIContainer.SQLDataAccess, DIContainer"/>
</typeAliases>
<container>
<register type="IDBAccess" mapTo="SQLDataAccess"/>
</container>
</unity>
var container = new UnityContainer();
var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);