C# 如何实现依赖注入容器 - 从零开始理解控制反转(IoC)
发布时间 - 2025-12-27 00:00:00 点击率:次依赖注入(DI)是实现控制反转(IoC)最常用方式,DI容器负责自动创建对象、解析依赖、管理生命周期;.NET内置Microsoft.Extensions.DependencyInjection为轻量标准生产级容器,手写简易容器有助于理解其注册、解析、缓存三大核心机制及生命周期管理原理。
依赖注入(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(LifeTime.Singleton); container.Register (LifeTime.Transient); var service = container.Resolve
(); // 自动注入 ILogger
关键点在于 Resolve 时用反射读取 UserService 构造函数,发现它需要 ILogger,再查注册表,递归构建——这就是“自动装配”的起点。
.NET 内置容器怎么用?实际项目四步走
生产环境直接用 Microsoft.Extensions.DependencyInjection,它已高度优化且与 ASP.NET Core 深度集成:
- 安装 NuGet 包:
Microsoft.Extensions.DependencyInjection - 创建容器:
var services = new ServiceCollection() - 注册服务(支持三种生命周期):
services.AddSingleton() services.AddScoped() services.AddTransient() - 构建并使用:
var sp = services.BuildServiceProvider();
var logger = sp.GetRequiredService();
注意:Scoped 在 Web 中通常按 HTTP 请求生命周期管理,需搭配 IServiceScope 使用,避免跨作用域访问。
为什么需要生命周期管理?常见陷阱提醒
生命周期不是可选项,而是资源安全的关键:
- Transient:每次 Resolve 都新建实例 → 适合无状态、轻量类(如 DTO 转换器)
-
Sco
ped:同作用域内复用(如一次 Web 请求中所有 Repository 共享同一个 DbContext)→ 避免并发修改或连接泄漏 - Singleton:整个应用生命周期唯一 → 不能持有 Scoped 或 Transient 类型的引用(会延长其生命周期,引发内存泄漏或状态污染)
典型错误:在 Singleton 服务里注入 Scoped 的 DbContext,会导致 DbContext 被长期持有,下次请求拿到的是脏数据或已释放的上下文。
基本上就这些。手写容器帮你拆解原理,.NET 内置容器帮你稳住生产。IoC 不是炫技,而是让类更专注职责、更易替换、更可测试——容器只是让这件事自动化而已。
# c#
# ai
# 注册表
# microsoft
# 作用域
# .net
# 为什么
# red
# 构造函数
# register
# 递归
# 接口
# var
# 并发
# 对象
# http
# 自动化
# 帮你
# 最常用
# 的是
# 是一个
# 给你
# 这就是
# 三大
# 这件事
# 三种
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
Laravel模型关联查询教程_Laravel Eloquent一对多关联写法
长沙企业网站制作哪家好,长沙水业集团官方网站?
Laravel如何使用Spatie Media Library_Laravel图片上传管理与缩略图生成【步骤】
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
如何彻底卸载建站之星软件?
如何在阿里云虚拟服务器快速搭建网站?
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
北京的网站制作公司有哪些,哪个视频网站最好?
Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用
Laravel API资源类怎么用_Laravel API Resource数据转换
Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中
如何彻底删除建站之星生成的Banner?
Laravel如何生成和使用数据填充?(Seeder和Factory示例)
如何解决hover在ie6中的兼容性问题
浅析上传头像示例及其注意事项
如何用JavaScript实现文本编辑器_光标和选区怎么处理
python中快速进行多个字符替换的方法小结
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?
微信小程序 input输入框控件详解及实例(多种示例)
Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册
微信小程序 配置文件详细介绍
HTML5打空格有哪些误区_新手常犯的空格使用错误【技巧】
详解Android图表 MPAndroidChart折线图
PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】
Windows Hello人脸识别突然无法使用
Laravel如何实现API资源集合?(Resource Collection教程)
详解Oracle修改字段类型方法总结
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
如何选择可靠的免备案建站服务器?
QQ浏览器网页版登录入口 个人中心在线进入
如何用IIS7快速搭建并优化网站站点?
关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)
zabbix利用python脚本发送报警邮件的方法
Laravel怎么实现软删除SoftDeletes_Laravel模型回收站功能与数据恢复【步骤】
Swift中swift中的switch 语句
Laravel怎么使用Markdown渲染文档_Laravel将Markdown内容转HTML页面展示【实战】
如何用5美元大硬盘VPS安全高效搭建个人网站?
Python正则表达式进阶教程_复杂匹配与分组替换解析
动图在线制作网站有哪些,滑动动图图集怎么做?
Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程
绝密ChatGPT指令:手把手教你生成HR无法拒绝的求职信
Laravel中DTO是什么概念_在Laravel项目中使用数据传输对象(DTO)
微信小程序 闭包写法详细介绍
Laravel怎么使用Session存储数据_Laravel会话管理与自定义驱动配置【详解】
如何基于云服务器快速搭建网站及云盘系统?
如何快速上传自定义模板至建站之星?
大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?
Laravel storage目录权限问题_Laravel文件写入权限设置


ped:同作用域内复用(如一次 Web 请求中所有 Repository 共享同一个 DbContext)→ 避免并发修改或连接泄漏