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

101 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.Scoped``MonoBehaviour` 不会自动销毁;需要通过层级管理或显式释放策略处理。
## 常见注册写法
- 注册具体类
- `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 选择标准),再大规模迁移。
## 参考页面
- About: https://vcontainer.hadashikick.jp/
- Installation: https://vcontainer.hadashikick.jp/getting-started/installation
- Hello World: https://vcontainer.hadashikick.jp/getting-started/hello-world
- Register Plain C# Type: https://vcontainer.hadashikick.jp/registering/register-type
- Lifetime Overview: https://vcontainer.hadashikick.jp/scoping/lifetime-overview
- Plain C# Entry point: https://vcontainer.hadashikick.jp/integrations/entrypoint
- Source Generator: https://vcontainer.hadashikick.jp/optimization/source-generator