# AutoRegisterExportedCollections 生成器

> 为 Godot 导出集合生成批量注册方法，收敛启动入口里的重复 `foreach + Registry(...)` 样板。

## 概述

在游戏启动入口中，常见的一类样板是：

- 在 Inspector 中导出一批配置、资源映射或预制体条目
- 从某个 Registry 成员拿到注册器
- 遍历集合逐项调用 `Register(...)` / `Registry(...)`

`AutoRegisterExportedCollections` 会把这类样板收敛成声明式配置。

它特别适合 `GameEntryPoint`、资源根节点、配置引导节点这类“导出即注册”的场景。
相关特性当前位于 `GFramework.Godot.SourceGenerators.Abstractions.UI` 命名空间。

## 基础使用

```csharp
using System.Collections.Generic;
using GFramework.Godot.SourceGenerators.Abstractions.UI;
using Godot;

public interface IKeyValue<TKey, TValue>
{
}

public interface IRegistry<TKey, TValue>
{
    void Registry(IKeyValue<TKey, TValue> mapping);
}

public interface IAssetRegistry<TValue> : IRegistry<string, TValue>
{
}

public sealed class TextureConfig : Resource, IKeyValue<string, Texture2D>
{
}

public sealed class TextureRegistry : IAssetRegistry<Texture2D>
{
    public void Registry(IKeyValue<string, Texture2D> mapping)
    {
    }
}

[AutoRegisterExportedCollections]
public partial class GameEntryPoint : Node
{
    private IAssetRegistry<Texture2D>? _textureRegistry;

    [Export]
    [RegisterExportedCollection(nameof(_textureRegistry), nameof(IRegistry<string, Texture2D>.Registry))]
    private Godot.Collections.Array<TextureConfig>? _textureConfigs;

    public override void _Ready()
    {
        _textureRegistry ??= new TextureRegistry();
        __RegisterExportedCollections_Generated();
    }
}
```

为了让示例具备完整的调用路径，这里在 `_Ready()` 里先初始化了 `_textureRegistry`。
实际项目里，这个字段通常来自架构容器、服务定位或外部注入；关键点是调用 `__RegisterExportedCollections_Generated()`
之前，注册器成员必须已经可用，否则生成代码会按设计静默跳过注册。

## 生成的代码

```csharp
// <auto-generated />
#nullable enable

partial class GameEntryPoint
{
    private void __RegisterExportedCollections_Generated()
    {
        if (this._textureConfigs is not null && this._textureRegistry is not null)
        {
            foreach (var __generatedItem in this._textureConfigs)
            {
                this._textureRegistry.Registry(__generatedItem);
            }
        }
    }
}
```

## 参数说明

### `[AutoRegisterExportedCollections]`

类级标记，声明该类型允许生成 `__RegisterExportedCollections_Generated()`。

### `[RegisterExportedCollection(registryMemberName, registerMethodName)]`

| 参数                   | 类型       | 说明                               |
|----------------------|----------|----------------------------------|
| `registryMemberName` | `string` | 当前类型上用于执行注册的字段或属性名               |
| `registerMethodName` | `string` | 注册方法名，例如 `Register` 或 `Registry` |

推荐优先使用 `nameof(...)` 表达式，而不是手写字符串。

## 支持的匹配规则

生成器会在编译期验证：

- 集合成员必须是实例字段，或可读的实例属性
- 集合类型必须可枚举
- 集合元素类型必须能在编译期推导
- 注册器成员必须是实例字段，或可读的实例属性
- 注册方法必须是单参数实例方法，且参数类型能接收集合元素类型

当前版本还支持从以下位置解析注册方法：

- 注册器具体类型本身
- 注册器基类
- 注册器实现的接口
- 继承链上的接口

这意味着像 `IAssetRegistry<T>` 继承 `IRegistry<TKey, TValue>` 的项目结构也能正常生成，不必再把注册器字段改成具体实现类型。

## 适用场景

推荐用于：

- `GameEntryPoint` 中的资源注册
- 场景启动时的配置条目注册
- Inspector 预配置的纹理、音频、Prefab、场景映射批量接入

不推荐用于：

- 注册前需要复杂过滤、去重、排序、条件判断的集合
- 需要记录失败项、错误聚合或回滚逻辑的批量导入
- 每个元素注册时都依赖额外上下文或副作用控制的流程

## 使用约束

- 目标类型必须是 `partial class`
- 不支持嵌套类
- 生成器不会自动调用 `__RegisterExportedCollections_Generated()`
- 非泛型 `IEnumerable` 之类无法推导元素类型的集合不受支持
- 注册方法必须对宿主类型可访问

## 诊断信息

| 诊断 ID                 | 含义                                                          |
|-----------------------|-------------------------------------------------------------|
| `GF_Common_Class_001` | 目标类型不是 `partial`，生成被跳过                                      |
| `GF_Common_Class_002` | 宿主类型已声明 `__RegisterExportedCollections_Generated()`，与生成代码冲突 |
| `GF_AutoExport_001`   | `AutoRegisterExportedCollections` 不支持嵌套类                    |
| `GF_AutoExport_002`   | 指定的注册器成员不存在                                                 |
| `GF_AutoExport_003`   | 注册器成员上找不到兼容的注册方法                                            |
| `GF_AutoExport_004`   | 被标记的成员不是可枚举集合                                               |
| `GF_AutoExport_005`   | 无法推导集合元素类型                                                  |
| `GF_AutoExport_006`   | 集合成员不是实例可读成员                                                |
| `GF_AutoExport_007`   | 注册器成员不是实例可读成员                                               |
| `GF_AutoExport_008`   | `RegisterExportedCollectionAttribute` 参数无效                  |

## 调用时机建议

推荐在以下时机之一调用生成方法：

- `_Ready()` 中，且在注册器字段已经准备好之后
- 启动入口的显式 `Initialize()` 或 `Bootstrap()` 方法中
- 测试中的装配阶段

不要在构造函数中调用，因为此时 Godot 导出字段和外部依赖通常还未准备完毕。

## 相关文档

- [源码生成器总览](./index)
- [游戏内容配置系统](/zh-CN/game/config-system)
