# IoC 包使用说明 ## 概述 IoC(Inversion of Control,控制反转)包提供了一个轻量级的依赖注入容器,用于管理框架中各种组件的注册和获取。通过 IoC 容器,可以实现组件间的解耦,便于测试和维护。 ## 核心类 ### [`IocContainer`](IocContainer.cs) IoC 容器类,负责管理对象的注册和获取。 **主要功能:** - 注册实例到容器 - 从容器中获取实例 - 类型安全的依赖管理 ## 核心方法 ### 1. Register 注册一个实例到容器中。 ```csharp public void Register(T instance) ``` **参数:** - `instance`: 要注册的实例对象 **使用示例:** ```csharp var container = new IocContainer(); // 注册各种类型的实例 container.Register(new PlayerModel()); container.Register(new GameSystem()); container.Register(new StorageUtility()); ``` ### 2. Get 从容器中获取指定类型的实例。 ```csharp public T Get() where T : class ``` **返回值:** - 返回指定类型的实例,如果未找到则返回 `null` **使用示例:** ```csharp // 获取已注册的实例 var playerModel = container.Get(); var gameSystem = container.Get(); // 如果类型未注册,返回 null var unknownService = container.Get(); // null ``` ## 在框架中的使用 ### Architecture 中的应用 IoC 容器是 [`Architecture`](../architecture/Architecture.cs) 类的核心组件,用于管理所有的 System、Model 和 Utility。 ```csharp public abstract class Architecture : IArchitecture where T : Architecture, new() { // 内置 IoC 容器 private readonly IocContainer _mContainer = new(); // 注册系统 public void RegisterSystem(TSystem system) where TSystem : ISystem { system.SetArchitecture(this); _mContainer.Register(system); // 注册到容器 // ... } // 获取系统 public TSystem GetSystem() where TSystem : class, ISystem => _mContainer.Get(); // 从容器获取 // Model 和 Utility 同理 } ``` ### 注册组件到容器 ```csharp public class GameArchitecture : Architecture { protected override void Init() { // 这些方法内部都使用 IoC 容器 // 注册 Model(存储游戏数据) RegisterModel(new PlayerModel()); RegisterModel(new InventoryModel()); // 注册 System(业务逻辑) RegisterSystem(new GameplaySystem()); RegisterSystem(new SaveSystem()); // 注册 Utility(工具类) RegisterUtility(new TimeUtility()); RegisterUtility(new StorageUtility()); } } ``` ### 从容器获取组件 ```csharp // 通过扩展方法间接使用 IoC 容器 public class PlayerController : IController { public void Start() { // GetModel 内部调用 Architecture.GetModel // Architecture.GetModel 内部调用 IocContainer.Get var playerModel = this.GetModel(); var gameplaySystem = this.GetSystem(); var timeUtility = this.GetUtility(); } } ``` ## 工作原理 ### 内部实现 ```csharp public class IocContainer { // 使用字典存储类型到实例的映射 private readonly Dictionary _mInstances = new(); public void Register(T instance) { var key = typeof(T); _mInstances[key] = instance; // 注册或覆盖 } public T Get() where T : class { var key = typeof(T); if (_mInstances.TryGetValue(key, out var retInstance)) { return retInstance as T; // 类型转换 } return null; } } ``` ### 注册流程 ``` 用户代码 ↓ RegisterSystem(system) ↓ IocContainer.Register(system) ↓ Dictionary[typeof(T)] = system ``` ### 获取流程 ``` 用户代码 ↓ this.GetSystem() ↓ Architecture.GetSystem() ↓ IocContainer.Get() ↓ Dictionary.TryGetValue(typeof(T)) ↓ 返回实例或 null ``` ## 使用示例 ### 基础使用 ```csharp // 1. 创建容器 var container = new IocContainer(); // 2. 注册服务 var playerService = new PlayerService(); container.Register(playerService); // 3. 获取服务 var service = container.Get(); service.DoSomething(); ``` ### 接口和实现分离 ```csharp // 定义接口 public interface IDataService { void SaveData(string data); string LoadData(); } // 实现类 public class LocalDataService : IDataService { public void SaveData(string data) { /* 本地存储 */ } public string LoadData() { /* 本地加载 */ return ""; } } public class CloudDataService : IDataService { public void SaveData(string data) { /* 云端存储 */ } public string LoadData() { /* 云端加载 */ return ""; } } // 注册(可以根据配置选择不同实现) var container = new IocContainer(); #if CLOUD_SAVE container.Register(new CloudDataService()); #else container.Register(new LocalDataService()); #endif // 使用(不需要关心具体实现) var dataService = container.Get(); dataService.SaveData("game data"); ``` ### 覆盖注册 ```csharp var container = new IocContainer(); // 首次注册 container.Register(new DefaultConfig()); // 后续注册会覆盖 container.Register(new CustomConfig()); // 获取到的是最后注册的实例 var config = container.Get(); // CustomConfig ``` ## 设计特点 ### 1. 简单轻量 - 只有两个核心方法:`Register` 和 `Get` - 基于字典实现,性能高效 - 无复杂的依赖解析逻辑 ### 2. 手动注册 - 需要显式注册每个组件 - 不支持自动依赖注入 - 完全可控的组件生命周期 ### 3. 单例模式 - 每个类型只能注册一个实例 - 适合管理全局单例服务 - 后续注册会覆盖前面的实例 ### 4. 类型安全 - 基于泛型,编译时类型检查 - 避免字符串键导致的错误 - IDE 友好,支持自动补全 ## 与其他 IoC 容器的区别 ### 本框架的 IocContainer ```csharp // 简单直接 var container = new IocContainer(); container.Register(new MyService()); var service = container.Get(); ``` **特点:** - ✅ 简单易用 - ✅ 性能高 - ❌ 不支持构造函数注入 - ❌ 不支持自动解析依赖 - ❌ 不支持生命周期管理(Transient/Scoped/Singleton) ### 完整的 IoC 框架(如 Autofac、Zenject) ```csharp // 复杂但功能强大 var builder = new ContainerBuilder(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().WithParameter("config", config); var container = builder.Build(); // 自动解析依赖 var controller = container.Resolve(); ``` **特点:** - ✅ 自动依赖注入 - ✅ 生命周期管理 - ✅ 复杂场景支持 - ❌ 学习成本高 - ❌ 性能开销大 ## 最佳实践 ### 1. 在架构初始化时注册 ```csharp public class GameArchitecture : Architecture { protected override void Init() { // 按顺序注册组件 // 1. 工具类(无依赖) RegisterUtility(new TimeUtility()); RegisterUtility(new StorageUtility()); // 2. 模型(可能依赖工具) RegisterModel(new PlayerModel()); RegisterModel(new GameModel()); // 3. 系统(可能依赖模型和工具) RegisterSystem(new GameplaySystem()); RegisterSystem(new SaveSystem()); } } ``` ### 2. 使用接口类型注册 ```csharp // ❌ 不推荐:直接使用实现类 RegisterSystem(new ConcreteSystem()); var system = GetSystem(); // ✅ 推荐:使用接口 RegisterSystem(new ConcreteSystem()); var system = GetSystem(); ``` ### 3. 避免运行时频繁注册 ```csharp // ❌ 不好:游戏运行时频繁注册 void Update() { RegisterService(new TempService()); // 每帧创建 } // ✅ 好:在初始化时一次性注册 protected override void Init() { RegisterService(new PersistentService()); } ``` ### 4. 检查 null 返回值 ```csharp // 获取可能不存在的服务 var service = container.Get(); if (service != null) { service.DoSomething(); } else { GD.Print("Service not registered!"); } ``` ## 注意事项 1. **类型唯一性** - 每个类型只能注册一个实例 - 重复注册会覆盖之前的实例 2. **手动管理依赖顺序** - 组件的依赖关系需要手动保证 - 先注册被依赖的组件 3. **无生命周期管理** - 实例一旦注册就一直存在 - 需要手动管理实例的生命周期 4. **线程安全** - 当前实现非线程安全 - 避免多线程同时访问 ## 扩展可能性 如果需要更复杂的功能,可以扩展 `IocContainer`: ```csharp // 支持工厂模式 public class AdvancedIocContainer : IocContainer { private Dictionary> _factories = new(); public void RegisterFactory(Func factory) where T : class { _factories[typeof(T)] = () => factory(); } public new T Get() where T : class { // 先尝试获取实例 var instance = base.Get(); if (instance != null) return instance; // 如果没有实例,尝试使用工厂创建 if (_factories.TryGetValue(typeof(T), out var factory)) { return factory() as T; } return null; } } ``` ## 相关包 - [`architecture`](../architecture/README.md) - 使用 IoC 容器管理所有组件 - [`model`](../model/README.md) - Model 通过 IoC 容器注册和获取 - [`system`](../system/README.md) - System 通过 IoC 容器注册和获取 - [`utility`](../utility/README.md) - Utility 通过 IoC 容器注册和获取