mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
- 新增 .claude/skills 目录及完整的文档生成技能系统 - 添加批量 API 文档生成脚本支持模块化文档创建 - 添加 API 文档、功能指南和教程生成模板与示例 - 添加 C# XML 注释解析和代码示例生成工具 - 添加文档验证和导航更新脚本确保质量 - 更新 .gitignore 配置排除本地设置文件
7.2 KiB
7.2 KiB
title, description
| title | description |
|---|---|
| IoC 容器使用指南 | IoC(控制反转)容器提供了轻量级的依赖注入功能,用于管理框架中各种组件的注册和获取。 |
IoC 容器使用指南
概述
IoC(Inversion of Control,控制反转)包提供了一个轻量级的依赖注入容器,用于管理框架中各种组件的注册和获取。通过 IoC 容器,可以实现组件间的解耦,便于测试和维护。
IoC 容器是 GFramework 架构的核心组件之一,为整个框架提供依赖管理和组件解析服务。
主要特性:
- 类型安全的依赖管理
- 支持单例和多实例注册
- 线程安全操作
- 容器冻结保护
- 自动接口注册
核心概念
依赖注入
依赖注入是一种设计模式,通过容器管理对象的创建和依赖关系,而不是在代码中直接创建对象。
// 不使用依赖注入
public class GameController
{
private PlayerModel model = new PlayerModel(); // 硬编码依赖
}
// 使用依赖注入
public class GameController : IController
{
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
public void Start()
{
var model = this.GetModel<PlayerModel>(); // 从容器获取
}
}
容器注册
在架构初始化时,将组件注册到容器中:
public class GameArchitecture : Architecture
{
protected override void Init()
{
// 注册 Model
RegisterModel(new PlayerModel());
// 注册 System
RegisterSystem(new GameplaySystem());
// 注册 Utility
RegisterUtility(new StorageUtility());
}
}
容器解析
通过扩展方法从容器中获取已注册的组件:
// 在 Controller 中
var playerModel = this.GetModel<PlayerModel>();
var gameplaySystem = this.GetSystem<GameplaySystem>();
var storageUtility = this.GetUtility<StorageUtility>();
基本用法
注册组件
var container = new IocContainer();
// 注册单例(一个类型只能有一个实例)
container.RegisterSingleton<IPlayerModel>(new PlayerModel());
// 注册多实例(一个类型可以有多个实例)
container.RegisterPlurality<IEnemy>(new Goblin());
container.RegisterPlurality<IEnemy>(new Orc());
container.RegisterPlurality<IEnemy>(new Dragon());
获取组件
// 获取单例
var playerModel = container.Get<IPlayerModel>();
// 获取多实例集合
var enemies = container.GetAll<IEnemy>(); // 返回 List<IEnemy>
在架构中使用
public class GameArchitecture : Architecture
{
protected override void Init()
{
// 注册组件
RegisterModel(new PlayerModel());
RegisterModel(new InventoryModel());
RegisterSystem(new GameplaySystem());
}
}
// 在 Controller 中使用
public class GameController : IController
{
public IArchitecture GetArchitecture() => GameArchitecture.Interface;
public void Start()
{
// 通过扩展方法获取组件
var playerModel = this.GetModel<PlayerModel>();
var inventoryModel = this.GetModel<InventoryModel>();
var gameplaySystem = this.GetSystem<GameplaySystem>();
}
}
高级用法
容器冻结
容器在架构初始化完成后会被冻结,防止运行时修改:
var container = new IocContainer();
container.Register<IPlayerModel>(new PlayerModel());
// 冻结容器
container.Freeze();
// 以下操作会抛出 InvalidOperationException
// container.Register<IGameSystem>(new GameSystem());
多实例管理
// 注册多个同类型实例
container.RegisterPlurality<IWeapon>(new Sword());
container.RegisterPlurality<IWeapon>(new Bow());
container.RegisterPlurality<IWeapon>(new Staff());
// 获取所有实例
var allWeapons = container.GetAll<IWeapon>();
foreach (var weapon in allWeapons)
{
weapon.Attack();
}
接口自动注册
注册实例时,容器会自动将其注册到所有实现的接口:
public class PlayerModel : IModel, IPlayerModel, IDisposable
{
// ...
}
// 注册实例
container.Register<PlayerModel>(new PlayerModel());
// 可以通过任何接口获取
var model1 = container.Get<IModel>();
var model2 = container.Get<IPlayerModel>();
var model3 = container.Get<IDisposable>();
// 以上三个变量指向同一个实例
线程安全操作
容器的所有操作都是线程安全的:
// 多线程环境下安全使用
Parallel.For(0, 100, i =>
{
var model = container.Get<IPlayerModel>();
model.DoSomething();
});
最佳实践
-
使用接口注册:优先使用接口类型注册,而不是具体类型
✓ container.Register<IPlayerModel>(new PlayerModel()); ✗ container.Register<PlayerModel>(new PlayerModel()); -
单例 vs 多实例:根据需求选择合适的注册方式
- 单例:全局唯一的服务(如配置、管理器)
- 多实例:可以有多个实例的对象(如敌人、道具)
-
避免循环依赖:组件之间不应该相互依赖
✗ System A 依赖 System B,System B 又依赖 System A ✓ 使用事件系统进行通信,避免直接依赖 -
在 Init 中注册:所有组件应该在架构的
Init()方法中注册protected override void Init() { // 在这里注册所有组件 RegisterModel(new PlayerModel()); RegisterSystem(new GameplaySystem()); } -
使用扩展方法:通过扩展方法获取组件,代码更简洁
✓ var model = this.GetModel<PlayerModel>(); ✗ var model = this.GetArchitecture().GetModel<PlayerModel>(); -
不要在运行时注册:容器冻结后不应该再注册新组件
✗ 在游戏运行时动态注册组件 ✓ 在架构初始化时注册所有需要的组件
常见问题
问题:如何判断使用单例还是多实例?
解答:
- 使用单例(
RegisterSingleton):全局唯一的服务,如 PlayerModel、GameConfiguration - 使用多实例(
RegisterPlurality):可以有多个实例的对象,如 Enemy、Weapon
问题:容器冻结后如何添加新组件?
解答: 容器冻结是为了保护架构稳定性。如果需要动态添加组件,应该:
- 在架构初始化时预先注册所有可能需要的组件
- 使用对象池模式管理动态对象
- 考虑使用工厂模式创建临时对象
问题:如何处理组件的生命周期?
解答:
- 实现
IDisposable接口的组件会在架构销毁时自动释放 - 架构会按注册的逆序销毁组件
- 不需要手动管理组件的生命周期
问题:可以在容器中注册值类型吗?
解答: 可以,但会发生装箱。建议将值类型包装在类中:
// 不推荐
container.Register<int>(42);
// 推荐
public class GameConfig
{
public int MaxPlayers { get; set; } = 42;
}
container.Register<GameConfig>(new GameConfig());
相关文档
- 架构组件 - 架构基础
- Model 层 - 数据模型
- System 层 - 业务系统
- Utility 工具类 - 工具类