DI 容器的注入顺序
目录
构造函数注入 → 属性注入 → 方法注入
为什么必须按这个顺序?
1)构造函数注入最先执行
像武侠入门——
一个对象的“根骨”和“基础武功”必须在创建时确定。
如果构造函数都没执行完,对象就不算真正存在。
所以只能放第一位。
DryIoc / Autofac / Unity 都遵守:
new MyService(构造函数参数...)2)属性注入(对象已经创建后)
对象创建出来后,才有属性可以赋值。
相当于:
【徒弟入门了 → 派发额外秘籍 → 装备 → 背景资料】
属性注入做的是:
obj.Property = container.Resolve<xxx>();它必须在构造函数之后执行。
3)方法注入最后执行
因为方法通常用于“最终初始化”或“准备阶段”:
- 有些依赖构造函数才能用
- 有些依赖可能来自属性注入
- 有些逻辑必须在对象完整初始化后才能运行
武侠比喻:
【入门 → 获得额外秘籍 → 大师兄带你走流程、告诉你门规】
方法注入是:
obj.Init(this.InjectMe(), that.InjectMe());必须最后。
标准容器的执行序列:
以 DryIoc(WPF/Prism 默认容器)为例:
① 解析构造函数
选择最长参数的构造函数(可解析的)
var service = new MyService(logger, repo);② 属性注入
扫描 [Inject] 或规则匹配的属性:
service.Cache = new MemoryCache()
service.Config = configProvider③ 方法注入
找到 [Inject] 方法:
service.Init(logger, cache)一个完整的例子
public class OrderService
{
private readonly ILogger _logger;
public ICache Cache { get; set; } // 属性注入
[Inject]
public void FinalizeInit(IConfig config) // 方法注入
{
_logger.Log("Config Loaded");
}
public OrderService(ILogger logger) // 构造注入
{
_logger = logger;
}
}DI 容器会这样执行:
第 1 步:构造函数注入
var logger = Resolve<ILogger>();
var obj = new OrderService(logger);第 2 步:属性注入
obj.Cache = Resolve<ICache>();第 3 步:方法注入
obj.FinalizeInit(Resolve<IConfig>());为什么顺序不能反过来?
如果属性注入在构造函数之前,你就会出现:
- 对象还没构造出来就试图给属性赋值 → 崩溃。
- 方法注入依赖构造函数中初始化的变量 → 变量为空,出现 NullReference。
这是容器工程级别的大忌。
对实际开发的意义
阶段能做什么构造函数必需依赖(不可或缺)属性注入可选依赖(非必须)方法注入初始化流程、复杂配置
WPF 开发中常用模式:
ViewModel 里:
- 主服务用构造函数注入(UserService、OrderService)
- 可选服务用属性注入(Logger、DialogService)
- 初始化 UI 的逻辑放在方法注入或 Prism 的 OnNavigatedTo
最核心的一句话总结:
一个对象必须先“出生”(构造函数),再“装备”(属性注入),最后“上阵”(方法注入)。
这就是:构造函数注入 → 属性注入 → 方法注入 的本质意义