Cnfzh 软件博客

从零实现一个迷你 IoC 容器

一百行代码理解依赖注入的三个核心抽象:注册、解析与生命周期。

为什么要自己写一个

框架用久了会忘掉底层在做什么。用一个周末写个迷你容器,把「注册」「解析」「生命周期」三件事各摸一遍,比读十篇源码解析都管用。

核心数据结构

容器本质上是一个字典:服务类型到「怎么造出来」的映射。造法分三种:给实例、给工厂、给实现类型。

private readonly Dictionary<Type, Func<IServiceProvider, object>> _registrations = new();

注册

AddSingleton 存实例;AddScoped 与 AddTransient 存工厂。三者的差别只在「每次解析要不要新建」。

解析

拿到注册项,构造实例。如果构造函数还有依赖,就递归解析——这就是「依赖图」的遍历。要注意循环依赖:A 等 B,B 又等 A,递归会栈溢出,成熟容器的做法是检测中的标记加报错。

生命周期

Singleton 实例存容器里,全局一份;Scoped 存在「作用域」对象里,每个请求一份;Transient 每次新建,谁也不存。迷你版可以把作用域做成一个子容器,解析时先查自己的注册表,找不到再问父容器。

踩到的坑

第一版忘了处理「解析未注册类型」,直接空引用。第二版把 Scoped 服务注册成了 Singleton,结果请求级的 DbContext 被全局复用,数据串了。生命周期不是性能问题,是正确性问题。

收获

写完再回头看 ASP.NET Core 的容器,那些 IServiceProvider、IServiceScope 的抽象突然都有了具体形状。框架是翅膀,但知道翅膀怎么扇的,掉下来时才不会慌。

评论 0

还没有评论,来说两句吧。

提交前需验证邮箱,验证码 10 分钟内有效。

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.