附加文件与配置生成 · 第 2 / 9 篇
文件级元数据不是 JSON 的一部分,它来自 MSBuild
很多人以为命名空间、类名和可见性都应该写在 JSON 里,但第二案例里,这些单文件覆盖项更适合来自 AdditionalFiles 元数据。
当生成器开始读 AdditionalFiles 时,最容易出现的设计冲动是:
“既然已经有 JSON 文件了,那命名空间、类名、可见性也一起写进 JSON 不就好了?”
这个思路表面上省事,长期看却很容易把职责搅乱。
为什么这些值不该优先放进 JSON
因为这几类信息,本质上不是业务内容,而是构建环境对某个输入文件的解释方式:
- 这个文件要生成到哪个命名空间
- 这个文件最终类名叫什么
- 输出是
public还是internal - 这个文件是不是应该显式参与当前生成
这些都更像项目配置,而不是资源文件内容本身。
更稳的边界应该是什么
在第二案例里,职责拆分应该尽量清楚:
- JSON 只负责
entries - 文件级元数据负责单文件覆盖项
- 项目级属性负责整项目默认值
这样做的好处是明显的:
- 资源文件作者不需要理解整个项目的输出策略
- 同一个 JSON 可以在不同项目里用不同元数据解释
- 生成器的覆盖优先级会更清晰
CompilerVisibleItemMetadata 为什么是关键
单文件元数据不是写上去就能被生成器看见。
如果项目里没有显式声明:
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="TutorialSettingsClassName" />
那么你在 AdditionalFiles 上写的自定义元数据,生成器默认是看不到的。
所以这条链路真正的结构是:
AdditionalFiles- 自定义 Item 元数据
CompilerVisibleItemMetadatabuild_metadata.AdditionalFiles.*AnalyzerConfigOptionsProvider.GetOptions(text)
少任何一步,这条链路都不成立。
为什么这比“把值塞进 JSON”更科学
因为它允许同一个文件内容,在不同项目或不同条目里被不同方式解释。
例如同一个 shared.release.json:
- 在一个项目里可以不参与生成
- 在另一个项目里可以通过
TutorialSettingsEnabled=true显式接入 - 在第三个项目里还可以被并到某个统一输出类里
如果这些行为都被写死在 JSON 里,配置复用空间会立刻变小。
这条链路最常见的误判
很多人看到“生成器没拿到我写的类名覆盖”,第一反应会去怀疑 JSON 解析。
但第二案例里更高概率的问题其实是:
- 没配置
CompilerVisibleItemMetadata - 键名写错
- 文件级元数据和项目默认值发生了覆盖
也就是说,这已经不是“文件内容读没读到”的问题,而是“项目元数据有没有进入编译器可见范围”的问题。
一句话结论
第二案例里,单文件覆盖项更适合来自 MSBuild 元数据,而不是继续往 JSON 里堆控制字段。
教程导航
继续阅读
当前文章已经挂到教程顺序中,建议按相邻章节继续。