# 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<PlayerModel>();
        var combatSystem = this.GetSystem<CombatSystem>();

        this.SendEvent(new PlayerInitializedEvent());
    }

    public void Attack(Enemy target)
    {
        var damage = this.GetUtility<DamageCalculator>().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
// <auto-generated/>
#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;

    /// <summary>
    /// 自动获取的架构上下文（懒加载，默认使用 GameContextProvider）
    /// </summary>
    protected global::GFramework.Core.Abstractions.Architecture.IArchitectureContext Context
    {
        get
        {
            if (_context == null)
            {
                _contextProvider ??= new global::GFramework.Core.Architecture.GameContextProvider();
                _context = _contextProvider.GetContext();
            }

            return _context;
        }
    }

    /// <summary>
    /// 配置上下文提供者（用于测试或多架构场景）
    /// </summary>
    /// <param name="provider">上下文提供者实例</param>
    public static void SetContextProvider(global::GFramework.Core.Abstractions.Architecture.IArchitectureContextProvider provider)
    {
        _contextProvider = provider;
    }

    /// <summary>
    /// 重置上下文提供者为默认值（用于测试清理）
    /// </summary>
    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<string, IArchitecture> _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<SaveSystem>();
        var uiSystem = this.GetSystem<UISystem>();

        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<PlayerModel>();
        var combatSystem = this.GetSystem<CombatSystem>();
    }
}
```

**说明**：

- `IController` 是标记接口，标识这是一个控制器
- `[ContextAware]` 提供架构访问能力
- 两者配合使用是推荐的模式

### 何时继承 ContextAwareBase

如果类需要更多框架功能（如生命周期管理），应继承 `ContextAwareBase`：

```csharp
// 推荐：需要生命周期管理时继承基类
public class PlayerModel : AbstractModel
{
    // AbstractModel 已经继承了 ContextAwareBase
    protected override void OnInit()
    {
        var config = this.GetUtility<ConfigLoader>().Load<PlayerConfig>();
    }
}

// 推荐：简单组件使用属性
[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<SomeModel>(); // 可能为 null
    }

    // ✅ 正确：在初始化方法中访问
    public void Initialize()
    {
        var model = this.GetModel<SomeModel>(); // 安全
    }
}
```

### 4. 优先使用 Context 属性而非接口方法

```csharp
[ContextAware]
public partial class MyController
{
    public void DoSomething()
    {
        // ✅ 推荐：使用扩展方法
        var model = this.GetModel<SomeModel>();

        // ❌ 不推荐：显式调用接口方法
        var context = ((IContextAware)this).GetContext();
        var model2 = context.GetModel<SomeModel>();
    }
}
```

## 诊断信息

生成器会在以下情况报告编译错误：

### 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)
