附加文件与配置生成 · 第 2 / 9 篇

文件级元数据不是 JSON 的一部分,它来自 MSBuild

很多人以为命名空间、类名和可见性都应该写在 JSON 里,但第二案例里,这些单文件覆盖项更适合来自 AdditionalFiles 元数据。

当生成器开始读 AdditionalFiles 时,最容易出现的设计冲动是:

“既然已经有 JSON 文件了,那命名空间、类名、可见性也一起写进 JSON 不就好了?”

这个思路表面上省事,长期看却很容易把职责搅乱。

为什么这些值不该优先放进 JSON

因为这几类信息,本质上不是业务内容,而是构建环境对某个输入文件的解释方式:

  • 这个文件要生成到哪个命名空间
  • 这个文件最终类名叫什么
  • 输出是 public 还是 internal
  • 这个文件是不是应该显式参与当前生成

这些都更像项目配置,而不是资源文件内容本身。

更稳的边界应该是什么

在第二案例里,职责拆分应该尽量清楚:

  • JSON 只负责 entries
  • 文件级元数据负责单文件覆盖项
  • 项目级属性负责整项目默认值

这样做的好处是明显的:

  • 资源文件作者不需要理解整个项目的输出策略
  • 同一个 JSON 可以在不同项目里用不同元数据解释
  • 生成器的覆盖优先级会更清晰

CompilerVisibleItemMetadata 为什么是关键

单文件元数据不是写上去就能被生成器看见。

如果项目里没有显式声明:

<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="TutorialSettingsClassName" />

那么你在 AdditionalFiles 上写的自定义元数据,生成器默认是看不到的。

所以这条链路真正的结构是:

  • AdditionalFiles
  • 自定义 Item 元数据
  • CompilerVisibleItemMetadata
  • build_metadata.AdditionalFiles.*
  • AnalyzerConfigOptionsProvider.GetOptions(text)

少任何一步,这条链路都不成立。

为什么这比“把值塞进 JSON”更科学

因为它允许同一个文件内容,在不同项目或不同条目里被不同方式解释。

例如同一个 shared.release.json

  • 在一个项目里可以不参与生成
  • 在另一个项目里可以通过 TutorialSettingsEnabled=true 显式接入
  • 在第三个项目里还可以被并到某个统一输出类里

如果这些行为都被写死在 JSON 里,配置复用空间会立刻变小。

这条链路最常见的误判

很多人看到“生成器没拿到我写的类名覆盖”,第一反应会去怀疑 JSON 解析。

但第二案例里更高概率的问题其实是:

  • 没配置 CompilerVisibleItemMetadata
  • 键名写错
  • 文件级元数据和项目默认值发生了覆盖

也就是说,这已经不是“文件内容读没读到”的问题,而是“项目元数据有没有进入编译器可见范围”的问题。

一句话结论

第二案例里,单文件覆盖项更适合来自 MSBuild 元数据,而不是继续往 JSON 里堆控制字段。

教程导航

继续阅读

当前文章已经挂到教程顺序中,建议按相邻章节继续。

上一篇 为什么 AdditionalFiles 才是第二阶段真正的开始 当生成器开始读取 AdditionalFiles、MSBuild 元数据和项目默认值时,它就不再只是演示案例,而是开始接近真实工程输入。 下一篇 全局默认值一旦进入生成器,契约边界就变了 项目级默认命名空间、类名和可见性不是便利配置而已,它们会直接改变生成器的输出契约和回退路径。
查看系列目录 查看全部文章

标签

分类