文档记录
This commit is contained in:
129
docs/requirements/p0-container.md
Normal file
129
docs/requirements/p0-container.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# P0-1: Container 需求详细文档
|
||||
|
||||
## 对齐说明
|
||||
|
||||
本文档以 `docs/requirements/p0-requirements-set.md` 为准。P0 允许 DI 自动注入进入首版,但必须保持 Container 核心轻量:核心只负责注册、解析、作用域和释放;Source Generator 与运行时反射只是生成工厂函数的适配层。
|
||||
|
||||
## 目标
|
||||
|
||||
提供 Game Core 的基础依赖容器,支持显式工厂注册、Attribute + Source Generator 自动注入、Attribute + 运行时反射降级、子作用域和可预测释放。
|
||||
|
||||
## P0 功能需求
|
||||
|
||||
### 1. 显式注册
|
||||
|
||||
```csharp
|
||||
public sealed class Container : IDisposable
|
||||
{
|
||||
public void RegisterInstance<T>(T instance);
|
||||
public void RegisterFactory<T>(Func<Container, T> factory);
|
||||
public T Resolve<T>();
|
||||
public bool TryResolve<T>(out T value);
|
||||
public Container CreateScope();
|
||||
public void Dispose();
|
||||
}
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- `RegisterInstance<T>` 注册外部实例,Container 不负责释放。
|
||||
- `RegisterFactory<T>` 首次 Resolve 时创建实例,后续返回同一实例。
|
||||
- 工厂创建且实现 `IDisposable` 的实例由当前 scope 释放。
|
||||
- 子 scope 可访问父 scope 注册。
|
||||
- 子 scope 可覆盖父 scope 注册,且不污染父 scope。
|
||||
- 已 Dispose 的 scope 调用 Register/Resolve 必须抛 `ObjectDisposedException`。
|
||||
|
||||
### 2. Attribute 自动注入
|
||||
|
||||
```csharp
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class InjectableAttribute : Attribute
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
public sealed class Container : IDisposable
|
||||
{
|
||||
public void RegisterType<TInterface, TImplementation>()
|
||||
where TImplementation : TInterface;
|
||||
|
||||
public void RegisterType<TImplementation>();
|
||||
public void RegisterAssembly();
|
||||
}
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
- 自动注入只支持构造函数注入。
|
||||
- 只允许一个 public 构造函数。
|
||||
- 构造函数参数从当前 Container 递归 Resolve。
|
||||
- 循环依赖必须检测,并输出完整依赖链。
|
||||
- `[Inject]` 属性注入和方法注入不进入 P0。
|
||||
|
||||
### 3. Source Generator 推荐路径
|
||||
|
||||
Source Generator 是 P0 推荐自动注入路径。
|
||||
|
||||
要求:
|
||||
|
||||
- 编译期扫描 `[Injectable]` 类型。
|
||||
- 为每个 Injectable 类型生成等价于手写工厂的静态工厂方法。
|
||||
- 编译期检查构造函数依赖是否可解析,无法确认时发出诊断。
|
||||
- Generator 程序集与 Runtime 程序集分离。
|
||||
- 未启用 Source Generator 时,显式工厂模式仍可独立使用。
|
||||
|
||||
### 4. 运行时反射降级路径
|
||||
|
||||
运行时反射是 P0 可选降级路径。
|
||||
|
||||
要求:
|
||||
|
||||
- 仅在启用反射模式时使用。
|
||||
- 反射只在首次 Resolve 时构造并缓存结果。
|
||||
- 行为必须与 Source Generator 模式一致。
|
||||
- IL2CPP/AOT 风险需要在文档中明确提示。
|
||||
|
||||
### 5. 释放规则
|
||||
|
||||
- 当前 scope Dispose 时按创建逆序释放本 scope 管理的 `IDisposable`。
|
||||
- 父 scope Dispose 时,先释放未释放的子 scope。
|
||||
- `Dispose()` 可重复调用,后续调用静默忽略。
|
||||
- 某个实例 Dispose 抛异常时,记录错误并继续释放其余实例。
|
||||
|
||||
## 暂不做
|
||||
|
||||
- `[Inject]` 属性注入。
|
||||
- `[Inject]` 方法注入。
|
||||
- Transient / Scoped / Singleton 多生命周期模式。
|
||||
- 开放泛型注册。
|
||||
- 装饰器注册。
|
||||
- 条件注册。
|
||||
- 运行时动态切换 DI 模式。
|
||||
|
||||
## 验收标准
|
||||
|
||||
| # | 标准 | 通过条件 |
|
||||
|---|------|---------|
|
||||
| 1 | 显式实例注册 | `RegisterInstance` 后 `Resolve` 返回同一实例 |
|
||||
| 2 | 显式工厂注册 | `RegisterFactory` 首次 Resolve 创建实例,后续复用 |
|
||||
| 3 | Source Generator 自动注入 | `[Injectable]` 类型可通过 `RegisterType` 正常解析 |
|
||||
| 4 | 运行时反射自动注入 | 反射模式下行为与 Source Generator 一致 |
|
||||
| 5 | 递归解析 | A 依赖 B、B 依赖 C 时 Resolve A 可自动解析整条链 |
|
||||
| 6 | 循环依赖检测 | A -> B -> A 抛异常,错误包含依赖链 |
|
||||
| 7 | 子 scope 读取父级 | 子 scope 可 Resolve 父 scope 注册 |
|
||||
| 8 | 子 scope 覆盖父级 | 子 scope 覆盖后父 scope 不受影响 |
|
||||
| 9 | 逆序释放 | 多个工厂实例按创建逆序 Dispose |
|
||||
| 10 | 外部实例不释放 | `RegisterInstance` 传入的实例不由 Container Dispose |
|
||||
| 11 | 重复 Dispose | 第二次 Dispose 不重复释放、不抛异常 |
|
||||
| 12 | 已释放 scope 防护 | 已 Dispose scope 调用 Register/Resolve 抛 `ObjectDisposedException` |
|
||||
|
||||
## 依赖关系
|
||||
|
||||
```text
|
||||
Container Runtime
|
||||
├── 纯 C#,不依赖 Unity API
|
||||
├── 不依赖 R3
|
||||
├── Source Generator 适配层依赖 Roslyn
|
||||
└── Reflection 适配层依赖 System.Reflection
|
||||
```
|
||||
Reference in New Issue
Block a user