ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

在 dotnet/runtime 中为新增公共 API 更新参考程序集(Reference Assembly)的完整指南

在 dotnet/runtime 中为新增公共 API 更新参考程序集(Reference Assembly)的完整指南 在 dotnet/runtime 中为新增公共 API 更新参考程序集Reference Assembly的完整指南【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime本文以 updating-ref-source.md 为核心骨架系统讲解在 .NET runtime 仓库中当向实现程序集implementation assembly添加新的公共 API后如何正确更新对应参考程序集reference assembly即ref目录下的 API 骨架源码。文章覆盖大多数库的标准流程、System.Runtime的特殊处理、Full Facade 程序集与 .NETFramework Facade 程序集的专属命令并结合仓库内的 ref 目录结构与源码佐证每一步的底层原理帮助读者在完成 API Review 后安全、无漂移地把新 API 同步进参考程序集并落地测试。为什么需要更新参考程序集在 .NET 的编译与运行时体系中同一份公共 API 存在两套源码一套位于src目录实现程序集包含真实的方法体与内部实现另一套位于ref目录参考程序集只保留公共 API 的签名骨架方法体为空或抛出异常。以仓库中的 System.Collections 为例其目录结构清晰地体现了这一分离src/libraries/System.Collections/ ├── ref/ # 参考程序集System.Collections.cs、System.Collections.Forwards.cs ├── src/ # 实现程序集 └── tests/ # 测试参考程序集的作用是对外发布一份稳定、不含实现细节的 API 契约编译器在编译用户代码时针对这份契约解析签名从而允许运行时自由调整内部实现而不破坏二进制兼容。因此每当实现程序集新增公共类型或成员都必须同步更新ref目录下的对应源文件否则新 API 无法被外部消费ApiCompat 校验也会失败。需要注意的是该更新流程的前提是 API 已经通过了 API Review即新 API 的命名与签名已获得正式评审认可本文不涉及 API 评审本身只解决评审通过之后如何落地的问题。大多数库的标准更新流程对于src/libraries下绝大多数程序集更新参考程序集遵循以下四步流程。步骤 1实现 API 并构建实现程序集先在实现程序集中完成新 API 的代码编写然后按照 构建单个库 的指引执行构建。一个常见的坑是新增公共类型时构建可能直接报TypeMustExist错误。这是因为参考程序集还缺少该类型而 ApiCompatAPI 兼容性校验在实现程序集中找不到对应契约时便拒绝继续。此时需要临时禁用 ApiCompat 的程序集校验来打破这个死锁dotnet build /p:ApiCompatValidateAssembliesfalse通过该参数跳过校验后即可进入下一步生成参考程序集源码。步骤 2用 GenAPI 工具重新生成参考程序集源码从src目录即src/libraries/程序集/src执行以下命令运行 GenAPI 工具dotnet msbuild /t:GenerateReferenceAssemblySourceGenAPI 会扫描实现程序集中的公共 API并重新生成ref目录下的参考源码。需要特别强调两点GenAPI 的输出往往存在大量噪音。仓库已知存在 GenAPI 生成大量不相关差异的问题见 dotnet/runtime 仓库 issue #100843因此生成后通常需要手工修正筛掉无关改动只保留与本次新 API 相关的差异例如可以忽略某些被移除的 attribute。不建议完全手工编辑参考源文件。完全手写会导致参考程序集与 GenAPI 工具的生成结果产生漂移drift使后续更新变得难以 diff并带来参考程序集与运行时程序集不一致的风险。正确姿势是以 GenAPI 输出为基础再做最小手工修正。步骤 3构建参考程序集生成或修正完源码后进入ref目录构建参考程序集项目。以仓库中的 System.Collections/ref/System.Collections.csproj 为参考参考程序集项目本质上是一个极简的类库项目Project SdkMicrosoft.NET.Sdk PropertyGroup TargetFramework$(NetCoreAppCurrent)/TargetFramework /PropertyGroup ItemGroup Compile IncludeSystem.Collections.cs / Compile IncludeSystem.Collections.Forwards.cs / /ItemGroup ItemGroup ProjectReference Include..\..\System.Runtime\ref\System.Runtime.csproj / /ItemGroup /Project从中可以读出两个重要事实参考程序集项目把System.Collections.cs与类型转发文件System.Collections.Forwards.cs一并编译并且它通过ProjectReference依赖 System.Runtime 的参考程序集——这也解释了为什么System.Runtime在整个 ref 体系中处于最底层、更新时需特殊对待见下文。步骤 4添加并运行测试新 API 不仅需要参考程序集与实现程序集还需要配套的测试位于程序集目录下的tests/文件夹。添加测试后执行构建与测试确认签名契约、实现与测试三者一致。补充已手工添加 API 后的重新生成注意如果你在生成参考源之前已经手工把新 API 加进了参考源文件那么在构建完实现程序集后重新执行GenerateReferenceAssemblySourceGenAPI 会将该 API全限定化fully qualified并归位到正确的排序位置。这种情况下命令从ref目录执行即可# 在 ref 目录下执行 dotnet msbuild /t:GenerateReferenceAssemblySource也就是说GenerateReferenceAssemblySource这个 target 在src与ref两个目录下都可运行只是适用场景不同src下运行是从实现生成参考源ref下运行是基于已有的参考源做规范整理。System.Runtime 的特殊流程System.Runtime是整个 .NET 类库的地基参考程序集且它直接依赖System.Private.CoreLib中的类型因此不能直接套用通用流程需要先构建底层再生成。适用场景这套流程同样适用于依赖 System.Private.CoreLib 变更的少数特殊程序集例如System.Memory这类 partial facade部分门面程序集——它们只转发System.Private.CoreLib中已定义类型的部分成员。操作步骤从System.Runtime/src目录执行以下命令注意多了--no-incremental确保不走增量缓存、完整重生成dotnet build --no-incremental /t:GenerateReferenceAssemblySource过滤无关变更由于System.Runtime参考源体量巨大生成结果中会混入大量与本次改动无关的差异例如某些 attribute 被移除。这一步需要手工把无关差异全部剔除只保留与你新增 API 相关的部分。文档明确指出Generally, this step is not required for other reference assemblies——即对其他参考程序集而言通常不需要这么麻烦唯独System.Runtime必须经历这一轮清理。仓库中可以看到System.Runtime的 src 目录下存在 System.Runtime.Typeforwards.cs说明该程序集的类型转发也是单独文件管理与 System.Runtime/ref 下的参考源配合维护。Full Facade 程序集的专属命令仓库中有一类实现程序集本质上是另一程序集的full facade完整门面自身几乎不承载实现却在参考程序集中定义类型。典型例子包括System.Runtime.Serialization.Json、System.Xml.XDocument等。对于这类程序集直接生成参考源会丢失类型转发关系必须显式让 GenAPI 跟随类型转发。对应的命令为dotnet msbuild /t:GenerateReferenceAssemblySource /p:GenAPIFollowTypeForwardstrue与标准命令相比多出的/p:GenAPIFollowTypeForwardstrue属性会指导 GenAPI 在遇到类型转发时沿着 TypeForwardedTo 继续展开从而把被转发类型的契约也纳入参考源生成范围保证门面程序集暴露出的 API 面完整。.NETFramework Facade 程序集手工补充类型转发还有一类更特殊的程序集它们在 .NETStandard 与 .NETCore 中定义类型但在 .NETFramework 目标上只是facade门面需要把类型转发到 .NETFramework 中既有类型所在的位置。这种情况下无法依赖 GenAPI 自动完成必须手工为 .NETFramework 构建下的参考程序集添加类型转发。具体要求如下对兼容的 .NETStandard 参考程序集中的每一个类型只要该类型在 .NETFramework 中已存在就必须为其添加TypeForwardedTo而对于那些在 .NETFramework 参考程序集中直接定义的类型则应当被抽取到**共享源文件shared source file**中供各目标框架复用避免重复定义。仓库中 System.Collections/ref/System.Collections.Forwards.cs 就是这种模式的具体呈现其内容非常简短本质上是带强约束注释的转发声明// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // ------------------------------------------------------------------------------ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Collections.ObjectModel.ReadOnlySet))]注意文件头部的注释Changes to this file must follow the https://aka.ms/api-review process.——任何对类型转发文件的改动都必须走 API Review 流程这与本文开头先评审、后更新的总体纪律完全一致。同时在 System.Collections/ref/System.Collections.csproj 中System.Collections.Forwards.cs与主参考源System.Collections.cs一起被Compile Include纳入编译印证了转发文件 契约文件并行维护的项目组织方式。常见问题与最佳实践小结场景命令 / 操作关键点大多数库标准流程从src目录执行dotnet msbuild /t:GenerateReferenceAssemblySource新增公共类型时先以/p:ApiCompatValidateAssembliesfalse打破TypeMustExist死锁已在 ref 中手工添加过 API从ref目录执行同一 targetGenAPI 会做全限定化并重新排序System.Runtime及依赖 CoreLib 的 partial facade从System.Runtime/src执行dotnet build --no-incremental /t:GenerateReferenceAssemblySource必须过滤无关差异只保留本次改动Full Facade 程序集如 System.Runtime.Serialization.Json、System.Xml.XDocumentdotnet msbuild /t:GenerateReferenceAssemblySource /p:GenAPIFollowTypeForwardstrue显式跟随类型转发保证契约完整.NETFramework Facade手工为 .NETFramework 参考程序集添加TypeForwardedTo框架内定义的类型抽入共享源文件需走 API Review改动遵守 ref 文件头部的评审注释约定贯穿全文的三条纪律值得在每一次 API 落地时自查先评审、再更新新增公共 API 前必须先完成 API Review参考程序集的任何变更都受此约束参考 ref 源文件 中的文件头注释约定。以 GenAPI 输出为基底而非全手工编写手工硬编码会导致参考程序集与工具生成结果漂移增加后续维护风险生成后的人工修正应聚焦于过滤噪音、保留本次改动。分层处理特殊程序集走特殊流程System.Runtime需要--no-incremental全量重建并人工清理Full Facade 需要GenAPIFollowTypeForwardstrue.NETFramework Facade 则需要手工维护类型转发。识别你正在处理的程序集属于哪一类直接决定命令与工作量。遵循上述流程即可保证新增公共 API 在实现程序集、参考程序集与测试三端保持一致让 API 契约稳定、可被编译器正确解析也避免了参考程序集与运行时程序集之间的漂移风险。【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表