1 定义
依赖注入(Dependency 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($"{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($"{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($"{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($"{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开发者指南