Skip to content

AutoRegisterExportedCollections 生成器

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

概述

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

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

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

它特别适合 GameEntryPoint、资源根节点、配置引导节点这类“导出即注册”的场景。

基础使用

csharp
using System.Collections.Generic;
using GFramework.Godot.SourceGenerators.Abstractions;
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)]

参数类型说明
registryMemberNamestring当前类型上用于执行注册的字段或属性名
registerMethodNamestring注册方法名,例如 RegisterRegistry

推荐优先使用 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_001AutoRegisterExportedCollections 不支持嵌套类
GF_AutoExport_002指定的注册器成员不存在
GF_AutoExport_003注册器成员上找不到兼容的注册方法
GF_AutoExport_004被标记的成员不是可枚举集合
GF_AutoExport_005无法推导集合元素类型
GF_AutoExport_006集合成员不是实例可读成员
GF_AutoExport_007注册器成员不是实例可读成员
GF_AutoExport_008RegisterExportedCollectionAttribute 参数无效

调用时机建议

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

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

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

相关文档

基于 Apache 2.0 许可证发布