1 定义
依赖注入(Depency Injection),简称DI,类之间的依赖关系由容器来负责。简单来讲a依赖b,但a不创建(或销毁)b,仅使用b,b的创建(或销毁)交给容器。
2 例子
为了把DI讲清楚,我们需要举一个简单例子。例子足够小,希望让你能直观的了解DI而不会陷入真实示例的泥潭。
例子:小明要杀怪,那小明拿什么武器杀怪呢?可以用刀、也可以用拳头、斧子等。
首先,我们创建一个演员类,名字叫“小明”,具有杀怪功能。
namespace NoInjection.ConsoleApp{ public class Actor { private string name = "小明"; public void Kill() { var knife = new Knife(); knife.Kill(name); } }}然后,我们再创建一个武器-刀类,具有杀怪功能。
using System;namespace NoInjection.ConsoleApp{ public class Knife { public void Kill(string name) { Console.WriteLine(#34;{name}用刀杀怪"); } }}最后,我们客户端调用演员类,执行杀怪功能。
using System;namespace NoInjection.ConsoleApp{ class Program { static void Main(string[] args) { var actor = new Actor(); actor.Kill(); Console.ReadKey(); } }}让我们来看看输出结果:
小明用刀杀怪通过这个例子我们可以看到,Actor类依赖Knife类,在Actor中创建Knife,执行Knife.Kill方法。我们可以回顾一下DI的定义,a依赖b,但a不创建(或销毁)b,仅使用b,显然这个不符合DI做法。
DI下面我们详细说说DI的几种形式。
3 形式
3.1 构造函数注入
首先,我们在Actor通过构造函数传入Knife。
namespace ConstructorInjection.ConsoleApp{ public class Actor { private string name = "小明"; private Knife knife; public Actor(Knife knife) { this.knife = knife; } public void Kill() { knife.Kill(name); } }}然后,Knife类不需要变化。
using System;namespace ConstructorInjection.ConsoleApp{ public class Knife { public void Kill(string name) { Console.WriteLine(#34;{name}用刀杀怪"); } }}最后,我们客户端来创建Actor和Knife,然后在Actor通过构造函数传入Knife。
using System;namespace ConstructorInjection.ConsoleApp{ class Program { static void Main(string[] args) { var knife = new Knife(); var actor = new Actor(knife); actor.Kill(); Console.ReadKey(); } }}让我们来看看输出结果:
小明用刀杀怪这个例子我们可以看到,Actor类依赖Knife类,但在Actor不创建Knife,而是通过构造函数传入Knife。
3.2 Setter注入
首先,我们在Actor类创建Knife属性。
namespace SetterInjection.ConsoleApp{ public class Actor { private string name = "小明"; private Knife knife; public Knife Knife { set { this.knife = value; } get { return this.knife; } } public void Kill() { knife.Kill(name); } }}然后,Knife类不需要变化。
using System;namespace SetterInjection.ConsoleApp{ public class Knife { public void Kill(string name) { Console.WriteLine(#34;{name}用刀杀怪"); } }}最后,我们客户端来创建Actor和Knife,然后在Actor通过属性传入Knife。
using System;namespace SetterInjection.ConsoleApp{ class Program { static void Main(string[] args) { var knife = new Knife(); var actor = new Actor(); actor.Knife = knife; actor.Kill(); Console.ReadKey(); } }}让我们来看看输出结果:
小明用刀杀怪这个例子我们可以看到,Actor类依赖Knife类,但在Actor不创建Knife,而是通过属性传入Knife。
3.3 接口注入
首先,我们在Actor类创建Knife属性并继承IActor
namespace InterfaceInjection.ConsoleApp{ interface IActor { Knife Knife { set; get; } void Kill(); }}namespace InterfaceInjection.ConsoleApp{ public class Actor: IActor { private string name = "小明"; private Knife knife; public Knife Knife { set { this.knife = value; } get { return this.knife; } } public void Kill() { knife.Kill(name); } }}然后,Knife类不需要变化。
using System;namespace InterfaceInjection.ConsoleApp{ public class Knife { public void Kill(string name) { Console.WriteLine(#34;{name}用刀杀怪"); } }}最后,我们客户端来创建Actor和Knife,然后在Actor通过属性传入Knife。
using System;namespace InterfaceInjection.ConsoleApp{ class Program { static void Main(string[] args) { var knife = new Knife(); IActor actor = new Actor(); actor.Knife = knife; actor.Kill(); Console.ReadKey(); } }}接口注入方式我理解了也不是很透,感觉跟Setter注入没有什么大的差别,只是增加了一个接口定义。
分类: ASP.NET Core开发者指南