Alva

Alva

programmer
github
telegram
email

dotnet 中的依赖注入-01.介绍

本文示例代码,均采用 .NET 6,具体的代码可以在这个仓库 Articles.DI 中获取。

让我们看这么一段简单的代码:

// https://github.com/alva-lin/Articles.DI/tree/master/WorkerService1
public class MessageWriter {
	public void Write(string message) => Console.WriteLine(message);
}

public class Worker : BackgroundService {
	private readonly MessageWriter _msgWriter = new MessageWriter();

	protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
		while (!stoppingToken.IsCancellationRequested) {
			_msgWriter.Write($"Worker running at: {DateTime.Now}");
			await Task.Delay(1000, stoppingToken);
		}
	}
}

在上面的代码中,Worker类包含有一个MessageWriter类的实例成员,这个类创建并直接依赖于MessageWriter类。这样的代码有一些问题:

  • 如果_msgWriter变量要替换成别种类型的实现,需要修改Worker类;
  • 如果MessageWriter类具有其他依赖项,则必须在Worker类中进行配置;
  • 难以对Worker类进行单元测试。

如果有一个统一的管理者,负责MessageWriter类型的实例化,然后将其传递给有需求的类,就能做到这两个类之间的依赖解除,减少了硬编码。而这,就是依赖注入。

依赖注入和控制反转#

依赖注入(英文 Dependency Injection,简称 DI),是一种在类及其依赖项之间实现控制反转(英文 Inversion of Control,简称 IoC)的技术。

控制反转,是面向对象编程中的一种设计原则,可以用来减少程序代码间的耦合程度。除了依赖注入外,还有一种实现控制反转的方法,叫做 “依赖查找”。

大多数程序都由多个类相互引用,彼此依赖合作以实现业务逻辑,这使得每个对象都需要获取其他服务的引用。如果这个获取过程需要靠对象自己实现,那么这将导致类之间高度耦合,难以维护和调试。

传统应用中,如果 A 服务要获取 B 服务,则需要在自己的代码块中实例化。而如果使用依赖注入,A 服务只需声明所需的服务,由外部容器来负责生成实例,A 服务只需接收即可。整个过程从主动变成了被动,反转了对象的获取过程,即实现了控制反转

下面两张图展示了两种依赖项关系图:

直接依赖项关系图

直接依赖项关系:类 A 调用类 B 的方法,类 B 调用类 C 的方法,则在编译时,类 A 依赖与类 B,类 B 依赖与类 C。

反转依赖项关系图

应用依赖反转后,类 A 引用的是接口 IB 的方法,不再直接依赖于类 B。在编译时,则是类 A 和类 B 引用了接口 IB,和前面的直接依赖相比,反转了依赖项。而类 B 和类 C 之间也是相似的。

IoC 解耦过程

这张图,生动形象的解释了控制反转是如何解耦服务之间的依赖。

参考链接#

依赖注入 - 维基百科

控制反转 - 维基百科

依赖关系反转 - 现代 ASP.NET Web 应用程序电子书

.NET 中的依赖关系注入

Inversion of Control Containers and the Dependency Injection pattern

依赖注入和控制反转的理解

控制反转(IoC)与依赖注入(DI)

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.