1. 首页
  2. >
  3. 编程技术
  4. >
  5. C#

什么是依赖注入

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开发者指南