目录

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

最核心的一句话总结:

一个对象必须先“出生”(构造函数),再“装备”(属性注入),最后“上阵”(方法注入)。

这就是:构造函数注入 → 属性注入 → 方法注入 的本质意义