# ContextAware 生成器 > 自动实现 IContextAware 接口,提供架构上下文访问能力 ## 概述 ContextAware 生成器为标记了 `[ContextAware]` 属性的类自动生成 `IContextAware` 接口实现,使类能够便捷地访问架构上下文( `IArchitectureContext`)。这是 GFramework 中最常用的源码生成器之一,几乎所有需要与架构交互的组件都会使用它。 ### 核心功能 - **自动接口实现**:无需手动实现 `IContextAware` 接口的 `SetContext()` 和 `GetContext()` 方法 - **懒加载上下文**:`Context` 属性在首次访问时自动初始化 - **默认提供者**:使用 `GameContextProvider` 作为默认上下文提供者 - **测试友好**:支持通过 `SetContextProvider()` 配置自定义上下文提供者 ## 基础使用 ### 标记类 使用 `[ContextAware]` 属性标记需要访问架构上下文的类: ```csharp using GFramework.SourceGenerators.Abstractions.Rule; using GFramework.Core.Abstractions.Controller; [ContextAware] public partial class PlayerController : IController { public void Initialize() { // 使用扩展方法访问架构([ContextAware] 实现 IContextAware 接口) var playerModel = this.GetModel(); var combatSystem = this.GetSystem(); this.SendEvent(new PlayerInitializedEvent()); } public void Attack(Enemy target) { var damage = this.GetUtility().Calculate(this, target); this.SendCommand(new DealDamageCommand(target, damage)); } } ``` ### 必要条件 标记的类必须满足以下条件: 1. **必须是 `partial` 类**:生成器需要生成部分类代码 2. **必须是 `class` 类型**:不能是 `struct` 或 `interface` ```csharp // ✅ 正确 [ContextAware] public partial class MyController { } // ❌ 错误:缺少 partial 关键字 [ContextAware] public class MyController { } // ❌ 错误:不能用于 struct [ContextAware] public partial struct MyStruct { } ``` ## 生成的代码 编译器会为标记的类自动生成以下代码: ```csharp // #nullable enable namespace YourNamespace; partial class PlayerController : global::GFramework.Core.Abstractions.Rule.IContextAware { private global::GFramework.Core.Abstractions.Architecture.IArchitectureContext? _context; private static global::GFramework.Core.Abstractions.Architecture.IArchitectureContextProvider? _contextProvider; /// /// 自动获取的架构上下文(懒加载,默认使用 GameContextProvider) /// protected global::GFramework.Core.Abstractions.Architecture.IArchitectureContext Context { get { if (_context == null) { _contextProvider ??= new global::GFramework.Core.Architecture.GameContextProvider(); _context = _contextProvider.GetContext(); } return _context; } } /// /// 配置上下文提供者(用于测试或多架构场景) /// /// 上下文提供者实例 public static void SetContextProvider(global::GFramework.Core.Abstractions.Architecture.IArchitectureContextProvider provider) { _contextProvider = provider; } /// /// 重置上下文提供者为默认值(用于测试清理) /// public static void ResetContextProvider() { _contextProvider = null; } void global::GFramework.Core.Abstractions.Rule.IContextAware.SetContext(global::GFramework.Core.Abstractions.Architecture.IArchitectureContext context) { _context = context; } global::GFramework.Core.Abstractions.Architecture.IArchitectureContext global::GFramework.Core.Abstractions.Rule.IContextAware.GetContext() { return Context; } } ``` ### 代码解析 生成的代码包含以下关键部分: 1. **私有字段**: - `_context`:缓存的上下文实例 - `_contextProvider`:静态上下文提供者(所有实例共享) 2. **Context 属性**: - `protected` 访问级别,子类可访问 - 懒加载:首次访问时自动初始化 - 使用 `GameContextProvider` 作为默认提供者 3. **配置方法**: - `SetContextProvider()`:设置自定义上下文提供者 - `ResetContextProvider()`:重置为默认提供者 4. **显式接口实现**: - `IContextAware.SetContext()`:允许外部设置上下文 - `IContextAware.GetContext()`:返回当前上下文 ## 配置上下文提供者 ### 测试场景 在单元测试中,通常需要使用自定义的上下文提供者: ```csharp [Test] public async Task TestPlayerController() { // 创建测试架构 var testArchitecture = new TestArchitecture(); await testArchitecture.InitAsync(); // 配置自定义上下文提供者 PlayerController.SetContextProvider(new TestContextProvider(testArchitecture)); try { // 测试代码 var controller = new PlayerController(); controller.Initialize(); // 验证... } finally { // 清理:重置上下文提供者 PlayerController.ResetContextProvider(); } } ``` ### 多架构场景 在某些高级场景中,可能需要同时运行多个架构实例: ```csharp public class MultiArchitectureManager { private readonly Dictionary _architectures = new(); public void SwitchToArchitecture(string name) { var architecture = _architectures[name]; var provider = new ScopedContextProvider(architecture); // 为所有使用 [ContextAware] 的类切换上下文 PlayerController.SetContextProvider(provider); EnemyController.SetContextProvider(provider); // ... } } ``` ## 使用场景 ### 何时使用 [ContextAware] 推荐在以下场景使用 `[ContextAware]` 属性: 1. **Controller 层**:需要协调多个 Model/System 的控制器 2. **Command/Query 实现**:需要访问架构服务的命令或查询 3. **自定义组件**:不继承框架基类但需要上下文访问的组件 ```csharp [ContextAware] public partial class GameFlowController : IController { public async Task StartGame() { var saveSystem = this.GetSystem(); var uiSystem = this.GetSystem(); await saveSystem.LoadAsync(); await uiSystem.ShowMainMenuAsync(); } } ``` ### 与 IController 配合使用 在 Godot 项目中,控制器通常同时实现 `IController` 和使用 `[ContextAware]`: ```csharp using GFramework.Core.Abstractions.Controller; using GFramework.SourceGenerators.Abstractions.Rule; [ContextAware] public partial class PlayerController : Node, IController { public override void _Ready() { // 使用扩展方法访问架构([ContextAware] 实现 IContextAware 接口) var playerModel = this.GetModel(); var combatSystem = this.GetSystem(); } } ``` **说明**: - `IController` 是标记接口,标识这是一个控制器 - `[ContextAware]` 提供架构访问能力 - 两者配合使用是推荐的模式 ### 何时继承 ContextAwareBase 如果类需要更多框架功能(如生命周期管理),应继承 `ContextAwareBase`: ```csharp // 推荐:需要生命周期管理时继承基类 public class PlayerModel : AbstractModel { // AbstractModel 已经继承了 ContextAwareBase protected override void OnInit() { var config = this.GetUtility().Load(); } } // 推荐:简单组件使用属性 [ContextAware] public partial class SimpleHelper { public void DoSomething() { this.SendEvent(new SomethingHappenedEvent()); } } ``` ## 与 IContextAware 接口的关系 生成的代码实现了 `IContextAware` 接口: ```csharp namespace GFramework.Core.Abstractions.Rule; public interface IContextAware { void SetContext(IArchitectureContext context); IArchitectureContext GetContext(); } ``` 这意味着标记了 `[ContextAware]` 的类可以: 1. **被架构自动注入上下文**:实现 `IContextAware` 的类在注册到架构时会自动调用 `SetContext()` 2. **参与依赖注入**:可以作为 `IContextAware` 类型注入到其他组件 3. **支持上下文传递**:可以通过 `GetContext()` 将上下文传递给其他组件 ## 最佳实践 ### 1. 始终使用 partial 关键字 ```csharp // ✅ 正确 [ContextAware] public partial class MyController { } // ❌ 错误:编译器会报错 [ContextAware] public class MyController { } ``` ### 2. 在测试中清理上下文提供者 ```csharp [TearDown] public void TearDown() { // 避免测试之间的状态污染 PlayerController.ResetContextProvider(); EnemyController.ResetContextProvider(); } ``` ### 3. 避免在构造函数中访问 Context ```csharp [ContextAware] public partial class MyController { // ❌ 错误:构造函数执行时上下文可能未初始化 public MyController() { var model = this.GetModel(); // 可能为 null } // ✅ 正确:在初始化方法中访问 public void Initialize() { var model = this.GetModel(); // 安全 } } ``` ### 4. 优先使用 Context 属性而非接口方法 ```csharp [ContextAware] public partial class MyController { public void DoSomething() { // ✅ 推荐:使用扩展方法 var model = this.GetModel(); // ❌ 不推荐:显式调用接口方法 var context = ((IContextAware)this).GetContext(); var model2 = context.GetModel(); } } ``` ## 诊断信息 生成器会在以下情况报告编译错误: ### GFSG001: 类必须是 partial ```csharp [ContextAware] public class MyController { } // 错误:缺少 partial 关键字 ``` **解决方案**:添加 `partial` 关键字 ```csharp [ContextAware] public partial class MyController { } // ✅ 正确 ``` ### GFSG002: ContextAware 只能用于类 ```csharp [ContextAware] public partial struct MyStruct { } // 错误:不能用于 struct ``` **解决方案**:将 `struct` 改为 `class` ```csharp [ContextAware] public partial class MyClass { } // ✅ 正确 ``` ## 相关文档 - [Source Generators 概述](./index) - [架构上下文](../core/context) - [IContextAware 接口](../core/rule) - [日志生成器](./logging-generator)