C# 如何实现依赖注入容器 - 从零开始理解控制反转(IoC)

来源:这里教程网 时间:2026-02-21 17:35:52 作者:

依赖注入(DI)是实现控制反转(IoC)最常用的方式,而 DI 容器就是负责自动创建对象、解析依赖、管理生命周期的核心组件。在 C# 中,.NET 自带的

Microsoft.Extensions.DependencyInjection
是轻量、标准、生产就绪的 IoC 容器;但要真正理解它,最好先“从零手写一个简易容器”——不是为了替代它,而是看清背后逻辑。

什么是控制反转(IoC)?

IoC 的本质是“把对象的创建和依赖关系的绑定,从代码内部转移到外部容器来管理”。以前你可能这样写:

var logger = new FileLogger();
var service = new UserService(logger); // 手动传入依赖

这导致类与具体实现强耦合,难测试、难替换。IoC 后,你只声明“我需要一个 ILogger”,容器负责给你合适的实例。

手写一个极简 DI 容器(核心三步)

下面是一个仅支持构造函数注入 + 单例/瞬时生命周期的 50 行容器原型,帮你抓住关键脉络:

注册(Register):告诉容器「某个接口对应哪个实现类,以及它的生命周期」 解析(Resolve):调用时,容器递归分析构造函数参数,自动 new 出完整对象树 缓存(Cache):对单例类型只创建一次,后续直接返回缓存实例
// 示例:注册与解析
container.Register<ILogger, ConsoleLogger>(LifeTime.Singleton);
container.Register<IUserService, UserService>(LifeTime.Transient);
<p>var service = container.Resolve<IUserService>(); // 自动注入 ILogger</p>

关键点在于 Resolve 时用反射读取

UserService
构造函数,发现它需要
ILogger
,再查注册表,递归构建——这就是“自动装配”的起点。

.NET 内置容器怎么用?实际项目四步走

生产环境直接用

Microsoft.Extensions.DependencyInjection
,它已高度优化且与 ASP.NET Core 深度集成:

安装 NuGet 包:
Microsoft.Extensions.DependencyInjection
创建容器:
var services = new ServiceCollection()
注册服务(支持三种生命周期):
services.AddSingleton<ilogger consolelogger>()</ilogger>

services.AddScoped<irepository sqlrepository>()</irepository>

services.AddTransient<inotifier emailnotifier>()</inotifier>
构建并使用:
var sp = services.BuildServiceProvider();<br>var logger = sp.GetRequiredService<ILogger>();

注意:

Scoped
在 Web 中通常按 HTTP 请求生命周期管理,需搭配
IServiceScope
使用,避免跨作用域访问。

为什么需要生命周期管理?常见陷阱提醒

生命周期不是可选项,而是资源安全的关键:

Transient:每次 Resolve 都新建实例 → 适合无状态、轻量类(如 DTO 转换器) Scoped:同作用域内复用(如一次 Web 请求中所有 Repository 共享同一个 DbContext)→ 避免并发修改或连接泄漏 Singleton:整个应用生命周期唯一 → 不能持有 Scoped 或 Transient 类型的引用(会延长其生命周期,引发内存泄漏或状态污染)

典型错误:在 Singleton 服务里注入 Scoped 的

DbContext
,会导致 DbContext 被长期持有,下次请求拿到的是脏数据或已释放的上下文。

基本上就这些。手写容器帮你拆解原理,.NET 内置容器帮你稳住生产。IoC 不是炫技,而是让类更专注职责、更易替换、更可测试——容器只是让这件事自动化而已。

相关推荐