扩展 Luban 导表流程:自动生成业务 ID
配置表有了类型定义之后,业务代码里仍然可能散落着很多数字 ID。读代码时需要回到表格查含义,复制到另一处时也容易写错。手工维护一份常量文件能够改善可读性,但会增加一份需要同步的数据。
我从 2025 年 9 月开始扩展项目的导表流程,让道具 ID 随导表一起生成。到 2026 年初,实体、界面、音效等类型也有类似需求,于是又把重复的输出流程抽成公共生成器,并继续接入 NPC ID。
让数据表成为唯一的数据来源
这里没有替换 Luban 的数据导出能力。Luban 先完成表格解析与数据输出,项目自己的后处理再读取导出结果,生成业务常量。
例如下面是一组虚构的配置:
| ID | 系统 | 名称 |
|---|---|---|
| 101 | Tool | 小铲子 |
| 102 | Tool | 喷壶 |
生成后,业务可以这样引用:
1 | public static class ItemId |
数值仍然来自配置表,常量名负责提供可读的访问入口。修改生成文件没有意义,下次导表就会被覆盖,因此文件头也明确标记为自动生成。
名称生成需要处理哪些约束
项目当时采用“系统名 + 名称拼音”的方式生成道具常量。这能减少不同系统之间的命名冲突,也让开发者在输入系统前缀后获得一组较容易辨认的提示。
生成前先检查系统字段能否对应到有效枚举。如果配置里填了不存在的系统值,应该在生成阶段报告所在数据,而不是输出一个看起来正常、实际含义不明的常量。
中文名转拼音之后仍然可能重名,因此实现中维护一个已用名称集合。再次遇到同名结果时,为后来的常量附加数据 ID,并输出警告。
1 | Tool_XiaoChanZi |
这是一种务实的兼容方式,但它并不保证名称永远不变。修改文案、调整重名项的先后顺序,都可能影响生成结果。需要长期稳定的引用时,更合适的是在表里提供单独的代码名字段,让展示文案与程序标识分别维护。
拼音也不是完整的 C# 标识符清洗。项目的名称约定能覆盖日常数据,并不意味着任意标点、数字开头或关键字都可以直接生成合法代码。这类情况需要在输入约束或生成器中明确处理,最后仍要通过编译检查。
重复的是输出流程,变化的是表格规则
生成器逐渐增多之后,很多代码开始重复:检查参数、创建命名空间、写注释、输出常量和建立目录。每增加一种表,就要复制一段基本相同的文件写入逻辑。
我把它们拆成两层:
| 层级 | 负责的事情 |
|---|---|
| 各表生成器 | 读取数据、选择条目、校验业务字段、决定常量名称 |
| 公共基类 | 组织 C# 结构、生成注释、输出常量或枚举、写入文件 |
上层向公共方法提供一组简单的数据项:常量名、ID 和描述。这样新增一种表时,关注点就落在“哪些条目需要生成、应该叫什么”,不必再次维护文件格式。
1 | public abstract class IdGenerator |
这里展示的是职责结构,省略了项目自己的数据类型。常量和枚举可以分别提供输出入口,不必为了统一形式强行把所有表都生成同一种声明。
发现和执行生成器
项目的生成器都位于同一个工具程序集里,因此加载器可以反射查找公共基类的非抽象派生类,筛选有无参构造函数的类型,再实例化并统一执行。
实际执行前按类型名排序,使同一组生成器的执行顺序确定。这个顺序只用于保持行为可预期,不应该承载隐含的跨生成器依赖;如果 B 必须读取 A 的结果,就需要显式安排依赖关系。
统一入口也方便同时为不同代码模块输出文件:表的读取和命名规则复用,命名空间、类名和目标目录则由对应生成器提供。
这次实现会记录单个生成器的异常,并继续尝试剩余生成器。这样的行为便于一次发现多个问题,但“后面的表生成完成”不能当作整个流程成功。接入自动构建时,需要汇总错误并通过失败状态阻止使用不完整的输出。
内容不变时跳过写入
即使生成结果完全相同,直接覆盖文件也会改变修改时间,增加文件监听、资源刷新或编译链路的无效工作。因此公共输出方法先比较内容:
1 | static void WriteWhenChanged(string outputPath, string content) |
要让这个比较有意义,生成内容本身也必须稳定。不要在每次输出里加入当前时间,也不要依赖无序集合决定条目顺序。输入与生成规则都没变化时,重复执行应得到相同文本。
常量能提前暴露哪些问题
使用命名常量后,删除或重命名配置导致某个符号消失,会在代码编译时暴露引用错误;使用者也可以通过注释看到这条配置的含义。
但常量只能覆盖编译期可见的引用。网络下发的 ID、存档里的旧 ID,以及运行时拼出的资源关系,仍然需要数据校验。生成代码不会自动证明所有配置引用都有效。
还有一个容易忽略的点:C# 的 const 会在编译时内联到调用方。如果生成常量与使用常量的程序集分开更新,必须确保依赖方也重新编译,不能只替换定义常量的程序集。
把约定放进可执行的流程
这次扩展最直接的收益,是业务不必手抄数字,新增表类型也可以沿同一个入口生成代码。命名与校验规则集中之后,后续调整有了明确的位置。
我保留各张表自己的选择和命名逻辑,只统一重复的输出部分。对于项目工具,这样的边界已经足够实用:规则写在生成器里,结果随导表产生,最终由编译和资源接入一起检查。
参考:Luban。