.NET Runtime 仓库添加新 API 全流程指南从库选择、GenAPI 参考源更新到 PlatformDocAnalyzer 文档约束【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime在 .NET runtime 仓库中向基础类库添加新的公开 API需要同时满足接口评审API Review、参考程序集同步、测试框架适配与 XML 文档规范四条主线。本文基于仓库中 adding-api-guidelines.md 的完整规范展开并结合 updating-ref-source.md 的参考源更新流程、PlatformDocAnalyzer 源码与 intellisense.targets 构建逻辑讲清在哪个库、哪个 TFM 加 API、如何用 GenAPI 更新参考源、如何写测试、三斜线文档放在哪、为什么放错了会被 CI 拦下的完整闭环。读完后你可以独立完成一次符合本仓库规范的新 API 提交。一、新增 API 前的三项决策选库、选 TFM、选版本1. 确定 API 应放在哪个库文档给出的第一步是先提出一个以哪个库作为暴露面的提案并走 API 评审流程原文链接指向 aka.ms/apireview 评审入口。评审的意义在于.NET 的 API 面是跨版本兼容承诺的核心任何新增公开 API 都必须在进入实现之前被评审确认命名空间归属与 API 形状。文档还特别强调一个容易踩坑的事实API 很可能暴露在一个与实现程序集身份不一致的参考程序集中。这样做的主要原因有两个跨平台抽象运行时程序集身份——同一份 API 面可以在不同平台上以不同的实现程序集身份出现而消费者编译时看到的参考程序集是统一的允许未来重构实现而不产生兼容性问题——只要参考程序集不变实现程序集的名称、内部拆分都可以自由演进。从仓库结构看这种实现面/参考面分离的布局在src/coreclr/System.Private.CoreLib运行时内部实现与对外 dlls 的划分中体现得很明显核心类型在System.Private.CoreLib中实现而公开契约由对应的参考程序集表达。2. 确定目标框架Target Framework文档明确规定net11.0是当前正在开发的目标框架版本新 API 应添加到net11.0。也就是说在本仓库当前开发线中新 API 一律落在net11.0这个 TFM 下而不是往更低版本的 TFM 里加。如果你的 API 需要平台后缀如net11.0-windows、net11.0-linux则后续文档放置规则会受 PlatformDocAnalyzer 约束见第五节。3. 确定库版本文档将Determine library version列为决策项之一具体版本号策略遵循仓库的发布/版本化规范参见 project-guidelines.md 中的项目级约定。实操中版本号的最终裁决同样在 API 评审阶段完成。二、在仓库中落地实现、参考源与测试1. 实现 API 修改在最合适的库项目中实现你的 API 修改Implement your API modification in the appropriate library project。2. 更新参考程序集GenAPI 流程新公开 API 落地后必须同步更新 ref 目录中的参考源详细步骤见 updating-ref-source.md。该文档给出的标准流程是在源程序集中实现 API 并构建。注意新增公开类型时构建可能因 ApiCompat 的程序集校验报TypeMustExist错误可临时用dotnet build /p:ApiCompatValidateAssembliesfalse绕过这一死锁在src 目录下运行 GenAPI 工具生成参考源dotnet msbuild /t:GenerateReferenceAssemblySource文档提醒GenAPI 可能产生大量不相关的 diff需要手动挑选你真正关心的改动不推荐完全手写参考源因为会与 GenAPI 生成结果产生漂移drift导致后续更新更难看清、且参考程序集与运行时程序集存在分叉风险。若你已提前手工加了 API重新执行GenerateReferenceAssemblySource从 ref 目录执行可将其扶正为全限定名并按正确排序放置进入 ref 目录构建参考程序集添加、构建并运行测试。该文档还覆盖了三类特殊场景这里一并给出命令System.Runtime 及部分依赖 System.Private.CoreLib 的程序集如 System.Memory 这类 partial facade从System.Runtime/src目录运行dotnet build --no-incremental /t:GenerateReferenceAssemblySource然后过滤掉无关改动此步其他参考程序集一般不需要Full Facade 程序集实现程序集是另一程序集上的完整 facade、但参考程序集中定义了类型如 System.Runtime.Serialization.Json、System.Xml.XDocumentdotnet msbuild /t:GenerateReferenceAssemblySource /p:GenAPIFollowTypeForwardstrue.NETFramework facade 程序集类型定义在 .NETStandard/.NETCore 中、在 .NETFramework 上只需转发type forward到既有位置的需要手工为 .NETFramework 参考程序集添加 TypeForwards——对每个在 .NETFramework 中已存在的、兼容 .NETStandard 参考程序集中的类型都要加转发定义在 .NETFramework 参考程序集中的类型应抽成共享源文件。3. 更新测试主文档要求将新的TargetFramework加入测试项目的TargetFrameworks列表针对新 TFM 的新文件遵循 代码文件命名约定 编写测试代码。该约定见 project-guidelines.md的核心规则是源文件与类一一对应文件名为class.cs按配置分叉的类命名为class.BuildSettings.cs$(TargetOS)/$(TargetFramework)/$(Configuration)/$(Platform)之一大小写严格一致按特性分叉的类命名为class.feature.cs如.CoreCLR.cs、.Win32.cs只运行新 TFM 的测试dotnet build Library.csproj -f TargetFramework /t:Test其中TargetFramework只能从受支持的 TargetFrameworks 中选择。三、文档规范三斜线注释与两条工作流基本规则所有新的公开 API必须以三斜线注释triple-slash comments写在符号上方。在 Visual Studio 中输入///会自动生成注释骨架如果新 API 或其调用的 API 会抛出异常必须手动用exception/exception元素补充文档——编译器不会替你推断异常契约语言风格遵循 .NET 官方 API 文档写作指南dotnet-api-docs wiki。工作流分叉取决于UseCompilerGeneratedDocXmlFile属性后续文档流程取决于该程序集项目文件中是否设置了UseCompilerGeneratedDocXmlFile属性。eng/intellisense.targets 中可以看到该属性默认为trueUseCompilerGeneratedDocXmlFile Condition$(UseCompilerGeneratedDocXmlFile) true/UseCompilerGeneratedDocXmlFile据此仓库中存在两种文档事实来源source of truth工作流A. 未设置该属性或为true即默认的库——源码注释即事实来源本仓库中的源码注释是文档的 source of truth源码三斜线注释会周期性地每个 preview同步到 dotnet-api-docs 仓库较新引入的库通常走这条流程。B. 将该属性显式设为false的库——dotnet-api-docs 仓库是事实来源文档以 dotnet-api-docs 仓库为准。你的改动合入 runtime 仓库后最终会把文档移植port到 dotnet-api-docs 仓库移植工具位于 api-docs-sync 仓库dotnet-api-docs 侧的改动合入后文档才会出现在官方 API 文档站点随后才进入 Visual Studio / Visual Studio Code 的 IntelliSense三斜线注释只在新 API 首次同步时被搬到 dotnet-api-docs。之后的所有文档更新必须直接在 dotnet-api-docs 仓库进行之后继续修改本地三斜线注释用于本地开发是可以的只是不会自动流入官方文档。小型改动可用 AI 辅助移植大型改动用 api-docs-sync 仓库提供的PortToDocs工具更合适较老的库通常走这条流程。文档也指出这类库未来可以通过 api-docs-sync 工具或 AI agent把 dotnet-api-docs 中的文档反向移植回源码注释然后移除UseCompilerGeneratedDocXmlFile属性从而迁移到更顺畅的 A 类工作流。从 intellisense.targets 的实现看当UseCompilerGeneratedDocXmlFile不为true时构建会从Microsoft.Private.Intellisense包中解析文档团队提供的 XMLDocFileOverride并在打包时用它替换编译器生成的文档文件ChangeDocumentationFileForPackaging目标同时会 NoWarn 掉 CS1591缺失 XML 注释警告。若文档团队未提供对应 XML构建还会发出明确警告提示移除该属性、改由编译器生成——这与上文两条工作流的判定完全对应。API 用法示例usage examples的规范用法示例放在测试源码中这样可以在常规测试运行中被验证。位置二选一取更贴合测试项目结构者放在examples子目录或文件名带Examples后缀。最终发布文档中要采用的具体代码用#region指令标出从而把[Fact]特性之类的测试样板排除在文档之外。在文档中引用示例的方式有两种在 XML 文档内引用在example元素内使用code langcs source... region... /元素在 Markdown 块内引用改用code-csharp指令。原文档给出的示例形式为!code-csharp[]注意原文中这条示例写的是相对文档自身位置的相对路径按本文的链接规范等价于仓库内tests/System.Text.RegularExpressions/FunctionalTests/Regex.Examples.cs中的Matchregion该示例路径为原规范文档中的写法具体示例文件以各库测试项目实际布局为准。这两种语法的本质相同按 region 从源文件中抽取指定代码片段直接内嵌进最终文档保证文档示例与可运行测试代码同源、不漂移。四、平台特定库中的文档放置规则这是本规范中最工程化的部分。当库同时面向平台特定 TFM如net11.0-windows、net11.0-linux时只会选择一个平台的编译器生成 doc XML作为事实来源、打进分发给所有客户的 IntelliSense 包。这意味着如果某个公开 API 的 XML 文档注释只写在平台特定的 partial 文件里那么在其他平台发布的文档中它就是缺失的。为保证跨平台文档一致规则有三条文档放在主源文件每个公开类型应有一个名为TypeName.cs的主源文件所有公开 API 的文档/// summary、/// param等都必须写在这个文件里partial 文件遵循命名约定平台或特性特定的 partial 文件必须命名为TypeName.Something.cs如Socket.Windows.cs、Socket.Unix.cs——这与 project-guidelines.md 的class.BuildSettings.cs约定一脉相承不要在非主 partial 文件中写公开 XML 文档注释若某公开成员声明在TypeName.Windows.cs中其文档应写在TypeName.cs中用 partial method 声明或inheritdoc/承接而不是写在平台特定文件里。PlatformDocAnalyzer规则的自动执法者上述规则由 PlatformDocAnalyzer位于eng/analyzers/PlatformDocAnalyzer强制执行该分析器自动应用于所有库源码项目。它的激活条件是构建平台特定的 TFM且UseCompilerGeneratedDocXmlFiletrue。四条诊断如下诊断说明PLATDOC001公开类型缺少名为TypeName.cs的源文件PLATDOC002partial 源文件不符合TypeName.Something.cs命名约定PLATDOC003非主 partial 文件中的公开成员带有 XML 文档应移到TypeName.csPLATDOC004某公开 API 的文档与无平台canonical构建中的文档不一致PLATDOC001–003 是启发式规则用于引导源码组织PLATDOC004 是权威性检查。从 PlatformDocAnalyzer.cs 的OnCompilationStart可以看到其工作机制分析器先读全局分析器配置build_property.TargetFramework只有当 TFM 名带平台后缀含-如net10.0-windows见IsPlatformSpecificTfm时才继续再读build_property.UseCompilerGeneratedDocXmlFile必须为true这两个 MSBuild 属性经 PlatformDocAnalyzer.props 声明的CompilerVisibleProperty暴露给分析器对 PLATDOC004构建侧会把 canonical TFM与平台 TFM 共存的那个无平台 TFM如net11.0-windows旁边的net11.0的编译器生成 doc XML 作为带PlatformDocCanonicaltrue元数据的 AdditionalFile 传入由 intellisense.targets 完成其注释明确写着Platform-specific builds: pass it to PlatformDocAnalyzer as an AdditionalFile分析器用正则而非 XML 解析器抽取member name....../member元素避免 XML 解析器的规范化处理造成与GetDocumentationCommentXml()输出的假性不匹配见 ParseDocXml 的注释再对每个公开类型及其公开成员将当前构建的文档与 canonical 文档做空白归一化后的逐字节比较NormalizeDocXml把连续空白折叠为单空格两者都为空视为一致任何差异即报 PLATDOC004。换句话说如果某平台 TFM 构建中某个 API 的文档与无平台 TFM 构建不一致几乎可以断定文档被写在了平台特定源文件上——这正是 PLATDOC004 要抓的失误。分析器只对跨多文件声明的类型做主文件检查单文件类型不存在文档放置问题PLATDOC002 还要求非主文件名严格以TypeName.前缀开头且以.cs结尾、且中间必须有内容。它的测试套件位于eng/analyzers/PlatformDocAnalyzer.Tests可用dotnet test eng/analyzers/PlatformDocAnalyzer.Tests/PlatformDocAnalyzer.Tests.csproj在本地运行据 eng/analyzers/README.md 说明这些测试不在主 CI 流水线中修改分析器时本地运行。合理的例外pragma 抑制如果某个文件合理地不符合上述约定例如沿用既定TypeNameAsync.cs模式的Asyncpartial应使用#pragma warning disable PLATDOCnnn抑制对应诊断并附一句简短注释说明原因。五、FAQ把类型下沉到更低的契约contract时怎么办原文档 FAQ 收录了一个高频问题当你要把类型移动下沉到更低的 contract 时该怎么办答案必须同时对两个 contract 做版本化version both contracts at the same time过渡期内两个项目之间临时使用项目引用project references在你移除了类型的原位置必须留下 type-forward以保持向后兼容。这与第二节中 .NETFramework facade 场景的手工 TypeForwards 要求呼应type forward 是本仓库维护 API 兼容性的基本手段凡是类型搬家旧坐标上必须留有转发。六、流程小结与检查清单把整条链路串起来一次合规的新 API 提交应满足决策确定归属库参考程序集身份可与实现不同、确定 TFM当前开发线为net11.0、确定版本并通过 API 评审实现在对应库项目实现 API参考源按 updating-ref-source.md 用dotnet msbuild /t:GenerateReferenceAssemblySource特殊程序集用对应变体命令更新 ref 目录避免手写漂移测试TargetFrameworks加入新 TFM文件命名遵循class.cs/class.BuildSettings.cs约定用dotnet build Library.csproj -f TargetFramework /t:Test单独验证文档三斜线注释覆盖全部公开 API 与异常示例放测试中的examples/或*Examples.cs、以#region圈出用code langcs source... region.../或!code-csharp[]引用平台一致性平台特定 TFM 下文档一律写在TypeName.cs主文件接受 PLATDOC001–004 检查合理例外用#pragma warning disable加注释抑制。完成以上六步新增 API 就能以实现与参考一致、测试可验证、文档跨平台一致的状态进入仓库的正式流水线。【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考