用途
该技能用于在修改 .NET/C# 代码之前,识别并处理可能影响下游消费者的破坏性变更。它特别适用于调用方不受控制的场景,例如 NuGet 库,或包含 PublicAPI.Shipped/Unshipped.txt、ApiCompat、多目标框架等标记的仓库。技能的核心观点是:可观察的契约通常比眼前代码片段更广,一次编译通过且测试全绿的修改仍可能破坏下游消费者、其他目标框架、友元程序集,或在下次构建时被重新生成覆盖。
主要能力
技能提供了一套系统化的检查与决策流程:
-
先检查,再修改:通过命令查找仓库实际存在的隐藏契约面,包括公共 API 门禁(PublicApiAnalyzers 或 ApiCompat/EnablePackageValidation)、多目标与条件编译、生成/分部代码、InternalsVisibleTo。只针对实际发现的契约面阅读对应参考文档。
-
识别四类隐藏契约面:
- 公共 API:重命名、移动、删除、重新签名公共成员,或更改可空性、泛型约束、裁剪/AOT 特性,都是绿色测试无法捕获的破坏性变更。仓库可能通过源码级(PublicAPI.*.txt)或二进制/包级(ApiCompat)两种不可互换的方式把关。
- 多目标与 #if:多目标或条件编译的代码可能为编辑器显示的目标构建成功,却破坏从未调用的目标。需要检查每个分支,包括非活动分支。
- 源生成与分部代码:类型可能跨多个文件分部,部分由源生成器、Razor 等生成。需要包含所有分部声明,并将生成文件视为派生内容。
- InternalsVisibleTo:internal 在解决方案范围内并非私有,测试和友元程序集绑定到 internal 成员。重命名、移动或删除 internal 成员可能破坏声明项目中没有引用的消费者。
-
提供安全变更模式:针对常见诱人但危险的修改,给出安全替代方案。例如:
- 为已发布方法添加可选参数会导致二进制破坏,应保留原方法并新增重载。
- 编辑 PublicAPI.Shipped.txt 会隐藏破坏,应保留已发布行,在 Unshipped.txt 中记录新表面。
- 向已发布公共接口添加成员会破坏所有现有实现者,应添加默认接口实现或新接口。
- 重命名已发布成员应添加新名称,保留旧名称作为 [Obsolete] 转发器。
- 重命名或删除 internal 成员且 InternalsVisibleTo 指向解决方案外程序集时,应保留旧 internal 名称作为 [Obsolete] 转发器。
- 重命名已发布成员的参数会破坏按名称传递的调用方,应保持原名称不变。
- 密封类、使成员非虚或收窄参数可空性应视为破坏性变更并升级处理。
- 更改 const 值或可选参数默认值应保留已发布常量/默认值,引入新命名成员或新重载。
- 更改某个目标下 #if 的值应视为该目标的行为变更并明确指出。
-
要求明确的兼容性说明:当保留旧入口点或偏离字面请求时,最终答案必须包含兼容性说明行,指明保留的确切旧签名、仍绑定到它的消费者以及避免的具体失败。
-
验证与升级:要求为每个目标框架构建和测试(dotnet test -f <tfm>),如果项目设置了 EnablePackageValidation,需运行 dotnet pack。在无法验证兼容性、更改公共成员可观察注解、无法跨所有目标框架保持一致、或只能编辑会被下次构建覆盖的生成输出时,应停止并升级。
使用方式
技能通过检查命令和参考文档引导工作流程。首先运行检查命令查找仓库中的标记,然后仅针对实际发现的契约面阅读 references/ 下的对应文档。参考文件包括:
- references/public-api.md:两种 API 门禁及其不可互换性,可空性/裁剪/AOT 作为可观察 API,[Obsolete] 垫片和类型转发器,抑制基线。
- references/multi-targeting.md:TFM、#if 和平台符号、RID,以及如何检查和重新把关每个目标。
- references/source-generation.md:分部类型、生成输出与签入源码、编辑生成器输入。
- references/internals-visible-to.md:友元/测试程序集和强名称密钥。
适用场景
适用于修改 .NET/C# 代码且调用方不受控制的场景,包括:
- 维护 NuGet 库
- 仓库包含 PublicAPI.Shipped/Unshipped.txt、ApiCompat、EnablePackageValidation 等标记
- 多目标框架项目
- 使用源生成器或分部类型的项目
- 使用 InternalsVisibleTo 的项目
- 需要评估某个修改是否为破坏性变更
- 需要审查 diff 中的兼容性影响
限制
技能本身不提供自动修复或代码生成,而是提供检查、决策和验证的指导。它要求用户根据实际发现的契约面选择参考文档,不能假设或背诵所有契约面。对于无法验证兼容性的公共 API 变更、可观察注解变更、无法跨所有目标框架保持一致的情况,技能要求停止并升级,而不是静默继续。技能不编造功能、收费、价格、平台、效果或使用步骤;缺失事实应明确写暂未提供。