Files
obsidian-notes/InBox/20260211-180200-VContainer-Unity-DI-文档笔记.md
Zane be34565854 11
2026-02-12 17:41:24 +08:00

4.2 KiB
Raw Blame History

VContainerUnity DI文档笔记

来源: https://vcontainer.hadashikick.jp/ 记录时间: 2026-02-11

一句话总结

VContainer 是面向 Unity 的高性能 DI 容器,核心是 LifetimeScope + 明确生命周期 + PlayerLoop EntryPoint,兼顾性能、可维护性与可测试性。

核心概念

  • LifetimeScope 是组合根Composition Root在这里集中做注册。
  • 依赖推荐通过构造函数注入,业务入口可以使用纯 C# 类,不必全部依赖 MonoBehaviour
  • 容器不可变Immutable强调线程安全和稳定性。

安装方式

  • OpenUPM推荐
    • 命令: openupm add jp.hadashikick.vcontainer
  • UPM Git URL
    • "jp.hadashikick.vcontainer": "https://github.com/hadashiA/VContainer.git?path=VContainer/Assets/VContainer#1.17.0"
  • 手动导入 .unitypackage
  • 官方要求: Unity 2018.4+

Hello World 最小流程

  1. 新建继承 LifetimeScope 的组件(如 GameLifetimeScope)。
  2. Configure(IContainerBuilder builder) 中注册依赖。
  3. 把该 LifetimeScope 挂到场景中的 GameObject。
  4. 通过构造函数自动注入依赖。
  5. 需要接入 Unity 生命周期时,使用 marker interface例如 ITickable)。

生命周期Lifetime

  • Singleton
    • 全容器共享一个实例。
    • 同一容器内同类型不能重复注册。
  • Transient
    • 每次 Resolve 新建实例。
  • Scoped
    • 每个 LifetimeScope 一份实例。
    • 子 Scope 与父 Scope 可以拥有各自实例。
    • Scope 销毁时会释放引用并调用已注册对象的 IDisposable

父子 Scope 规则要点:

  • 子 Scope 找不到注册时会向父 Scope 查找。
  • 父子都注册了同类型时,优先使用“最近的 Scope”。
  • 注意:如果仅销毁 LifetimeScope,注册为 Lifetime.ScopedMonoBehaviour 不会自动销毁;需要通过层级管理或显式释放策略处理。

常见注册写法

  • 注册具体类
    • builder.Register<ServiceA>(Lifetime.Singleton);
  • 以接口注册
    • builder.Register<IServiceA, ServiceA>();
  • 多接口注册
    • builder.Register<ServiceA>(Lifetime.Singleton).As<IServiceA, IInputPort>();
  • 自动注册已实现接口
    • builder.Register<ServiceA>(Lifetime.Singleton).AsImplementedInterfaces();
  • 同时保留接口与自身类型
    • builder.Register<ServiceA>(Lifetime.Singleton).AsImplementedInterfaces().AsSelf();
  • 实例注册
    • builder.RegisterInstance(obj);
    • 注意:RegisterInstance 默认等同单例,但实例生命周期不由容器托管(不会自动 Dispose、不会自动做方法注入)。

Plain C# EntryPoint推荐实践

  • 使用 builder.RegisterEntryPoint<T>() 把纯 C# 类挂到 VContainer 自己的 PlayerLoop。
  • 可用接口与大致时机:
    • IInitializable / IPostInitializable
    • IStartable / IAsyncStartable / IPostStartable
    • IFixedTickable / IPostFixedTickable
    • ITickable / IPostTickable
    • ILateTickable / IPostLateTickable
    • IDisposable(随容器释放)
  • 未捕获异常可用 RegisterEntryPointExceptionHandler 自定义处理。

性能与优化

  • 官方定位:相对 Zenject 在 Resolve 路径上更快、GC 更低。
  • 默认使用反射;可启用 Source Generator 提升运行时性能。
  • Source Generator 要求 Unity 2021.3+;从 v1.13.0 起基于 Roslyn Source Generator。

我的落地建议Unity 项目)

  • LifetimeScope 当成“模块边界”,按场景/系统拆分父子 Scope。
  • 业务逻辑放纯 C#MonoBehaviour 尽量薄,只做视图与桥接。
  • 高频路径优先构造函数注入,减少运行期反射与临时分配。
  • 先统一生命周期约定Singleton/Scoped/Transient 选择标准),再大规模迁移。

参考页面