附加文件与配置生成 · 第 3 / 9 篇
全局默认值一旦进入生成器,契约边界就变了
项目级默认命名空间、类名和可见性不是便利配置而已,它们会直接改变生成器的输出契约和回退路径。
只要项目开始给生成器提供全局默认值,很多行为就不再是“文件自己决定”了。
这也是第二案例和第一案例最明显的分界之一。
为什么全局默认值不是附属能力
看上去,项目级默认值只是为了少写几次重复配置,比如:
- 默认命名空间
- 默认类名
- 默认可见性
但它真正影响的,是生成器的契约边界。
因为一旦默认值进入系统,生成器面对“不完整输入”时的解释方式就变了。
什么叫“契约边界变了”
在没有全局默认值时,缺了某些配置,生成器可能只能:
- 回退到文件名约定
- 回退到 JSON 里的显式值
- 或者直接报错
但有了全局默认值之后,系统就多了一层正式兜底。
这意味着:
- 原本会靠文件名约定推导的类名,可能先被全局默认类名吃掉
- 原本需要逐文件设置的可见性,可能被项目级默认值统一收敛
- 原本只是“单文件行为”,现在可能会被项目环境整体改写
为什么这会影响回归风险
因为全局默认值一旦变更,受影响的不是某一个输入文件,而是整批没有显式覆盖的文件。
所以第二案例里,最需要测试锁定的往往不是“某个 JSON 能不能读出来”,而是:
- 文件级元数据是否真的覆盖全局默认值
- 全局默认值缺失时,是否才会回退到文件名约定
- 目录约定是不是建立在默认命名空间之上
这类问题一旦漏测,回归半径会比第一案例大很多。
为什么它必须走 CompilerVisibleProperty
项目级默认值的核心价值,不在于“有个地方可以配置”,而在于它是编译阶段可见的一层正式输入。
也就是说,生成器拿到的不是应用运行时配置,而是:
PropertyGroupCompilerVisiblePropertybuild_property.*
这条链路决定了它可以稳定进入 Roslyn 的 GlobalOptions。
第二案例里最容易被忽略的一点
很多人以为“全局默认值就是最弱的兜底”。
其实不是。
它虽然通常低于文件级元数据,但经常高于:
- JSON 里的某些字段
- 文件名约定
- “什么都不填”的默认回退
所以它不是可有可无的小补丁,而是一层真正会改变系统行为的配置层。
一句话结论
当全局默认值进入生成器之后,你设计的就不再只是单文件解析规则,而是一套项目级输出契约。
教程导航
继续阅读
当前文章已经挂到教程顺序中,建议按相邻章节继续。