控制反转(Inversion of Control)
控制反转(Inversion of
Control)是解决程序耦合问题的一种方案,还有种叫法是依赖注入(Dependency Injection),但我感觉Ioc(控制反转)是一种思想,DI(依赖注入)是实现这种思想的一种方式。
依赖倒置原则:
高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
抽象不应该依赖于具体,具体应该依赖于抽象。
依赖注入(Dependency Injection)
1.构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象。
/// <summary>
/// 人接口
/// </summary>
public interface IPeople
{
void DrinkWater();
}
/// <summary>
/// 村民
/// </summary>
public class VillagePeople : IPeople
{
IWaterTool _pw;
public VillagePeople(IWaterTool pw)
{
_pw = pw;
}
public void DrinkWater()
{
IWater uw = _pw.returnWater();
if (uw != null)
{
Console.WriteLine("水好甜啊!!!");
}
}
}
/// <summary>
/// 压水井
/// </summary>
public class PressWater : IWaterTool
{
public IWater returnWater()
{
return new UndergroundWater();
}
}
/// <summary>
/// 获取水方式接口
/// </summary>
public interface IWaterTool
{
IWater returnWater();
}
/// <summary>
/// 地下水
/// </summary>
public class UndergroundWater : IWater
{ }
/// <summary>
/// 水接口
/// </summary>
public interface IWater
{ }
class Program
{
static void Main(string[] args)
{
UnityContainer container = new UnityContainer();
container.RegisterType<TestFour.IWaterTool, TestFour.PressWater>();
TestFour.IPeople people = container.Resolve<TestFour.VillagePeople>();
people.DrinkWater();
}
}
2.属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性。
属性注入只需要在属性字段前面加[Dependency]标记就行了
/// <summary>
/// 村民
/// </summary>
public class VillagePeople : IPeople
{
[Dependency]
public IWaterTool _pw { get; set; }
public void DrinkWater()
{
Console.WriteLine(_pw.returnWater());
}
}
调用方式和构造器注入一样,通过RegisterType<Test02.IWaterTool, Test02.PressWater>();注入就可以了,除了使用RegisterType方法注册,我们还可以在配置文件中注册,[Dependency]和RegisterType方式其实都会产生耦合度,我们要添加一个属性或是修改一中注册都会去修改代码,我们要做的就是代码不去修改,只要修改配置文件了,这个在下面有讲解,这边就不多说,我们先看下使用UnityConfigurationSection的Configure方法加载配置文件注册:
<unity>
<containers>
<container name="defaultContainer">
<register type="UnityContainerDemo.IWaterTool,UnityContainerDemo" mapTo="UnityContainerDemo.PressWater,UnityContainerDemo"/>
<register type="UnityContainerDemo.IPeople,UnityContainerDemo" mapTo="UnityContainerDemo.VillagePeople02,UnityContainerDemo"/>
</container>
</containers>
</unity>
调用代码:
public static void FuTest02()
{
UnityContainer container = new UnityContainer();//创建容器
UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
configuration.Configure(container, "defaultContainer");
IPeople people = container.Resolve<IPeople>();//返回调用者
people.DrinkWater();//喝水
}
3、方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。
方法注入和属性方式使用一样,方法注入只需要在方法前加[InjectionMethod]标记就行了,从方法注入的定义上看,只是模糊的说对某个方法注入,并没有说明这个方法所依赖的对象注入,所依赖的对象无非就三种:参数、返回值和方法内部对象引用,我们做一个示例试下:
/// <summary>
/// 村民
/// </summary>
public class VillagePeople03 : IPeople
{
public IWaterTool tool;//我是对象引用
public IWaterTool tool2;//我是参数
public IWaterTool tool3;//我是返回值
[InjectionMethod]
public void DrinkWater()
{
if (tool == null)
{ }
}
[InjectionMethod]
public void DrinkWater2(IWaterTool tool2)
{
this.tool2 = tool2;
}
[InjectionMethod]
public IWaterTool DrinkWater3()
{
return tool3;
}
}
调用代码:
public static void FuTest03()
{
UnityContainer container = new UnityContainer();//创建容器
UnityConfigurationSection configuration = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
configuration.Configure(container, "defaultContainer");
VillagePeople03 people = container.Resolve<IPeople>() as VillagePeople03;//返回调用者
Console.WriteLine("people.tool == null(引用) ? {0}", people.tool == null ? "Yes" : "No");
Console.WriteLine("people.tool2 == null(参数) ? {0}", people.tool2 == null ? "Yes" : "No");
Console.WriteLine("people.tool3 == null(返回值) ? {0}", people.tool3 == null ? "Yes" : "No");
}
container.Resolve
结果不言而喻,其实我们理解的方法注入就是对参数对象的注入,从typeConfig节点-method节点-param节点就可以看出来只有参数的配置,而并没有其他的配置,关于typeConfig下面会讲到。
4、非泛型注入
除了我们上面使用RegisterType和Resolve泛型方法,我们也可以使用非泛型注入。
代码如下:
public static void FuTest04()
{
UnityContainer container = new UnityContainer();//创建容器
container.RegisterType(typeof(IWaterTool), typeof(PressWater));//注册依赖对象
IPeople people = (IPeople)container.Resolve(typeof(VillagePeople01));//返回调用者
people.DrinkWater();//喝水
}