如何为 .NET API 参考文档编写优秀的 /// 文档

.NET API 文档的最终目标是将 .NET 源代码中的 /// XML 注释作为“事实来源”。 对于 MSBuild、ASP.NET Core 和 EF Core,已实现此目标。 但是,目前 dotnet-api-docs 存储库 仍然是核心 .NET API 参考的真相来源。 此 dotnet/runtime 问题 跟踪支持 .NET 文档的努力,并使 dotnet/runtime 存储库成为事实来源。

本文提供有关在 源代码本身中编写良好文档注释的提示。

优质的评论成就优质文档

.NET API 三斜杠注释会被转换为发布在 learn.microsoft.com 上的公共文档,并在 IDE 中的 IntelliSense 中显示。 注释应为:

  • 完成 — 方法、参数、异常等的空文档条目,使 API 感觉不受支持、暂时或微不足道。
  • 正确——读者会扫描关键信息,当发现关键信息缺失或不正确时,他们会感到沮丧。
  • 上下文 - 读者从搜索中访问此页面,需要了解 API 的使用方式和时间,以及代码的含义。
  • 抛光 — 糟糕或匆匆的语法和拼写可能会混淆读者, 甚至简单的调用不明确;此外,糟糕的演示传达了低投资。

最佳做法

  1. 使用 cref 而不是 href 链接到其他类型或方法。

    正确:<param name="configFile">An <see cref="XmlConfigResource" /> object.</param>

    不正确:<param name="configFile">An <a href="https://learn.Microsoft.com/{path}/XmlConfigResource"></a> object.</param>

  2. 引用参数时,将参数名称包装在标记中 <paramref> ,例如 The offset in <paramref name="source" /> where the range begins.

  3. 如果文档注释中有多个段落,请使用标记分隔段落 <para>

  4. 将代码示例包装在 <code> 标记中的标记中 <example>

  5. 用于 <seealso> 在自动生成的“另请参阅”部分添加指向其他 API 的链接。

XML 文档标记

标记 目的 示例:
<altmember> 向指定的 API 添加“另请参阅”链接。 <altmember cref="System.Console.Out" />
<c> 将指定文本的格式设置为说明中的代码。 Gets the current version of the language compiler, in the form <c>Major.Minor.Revision.Build</c>.
<code> 将多行格式化为代码。 <code language="csharp">using(logger.BeginScope("Processing request from {Address}", address)) { }</code>
<example> 在“示例”H2 标题下添加代码示例。 <example><code language="csharp">using(logger.BeginScope("Processing request from {Address}", address)) { }</code></example>
<exception> 描述 API 可以引发的异常。 <exception cref="T:System.ArgumentException">No application identity is specified in <paramref name="identity" />.</exception>
<include> 请参阅另一个文件中描述源代码中 API 的注释。 <include file="../docs/AbsoluteLayout.xml" path="Type[@FullName='Microsoft.Maui.Controls.AbsoluteLayout']/Docs/*" />

.NET MAUI 示例
<inheritdoc> 从基类、接口和类似方法继承 XML 注释。 <inheritdoc />
<list> 创建编号列表或项目符号列表。 <list type="bullet"><item><description>Set the root path to the result.</description></item><item><description>Load host configuration.</description></item></list>
<para> 分隔段落。
<paramref> 指的是一个方法参数。 Returns the activity with the specified <paramref name="id" />.
<related> 向指定文章添加“另请参阅”链接。 <related type="Article" href="/dotnet/framework/ado-net-overview">ADO.NET overview</related>
<see cref> 指向另一个 API 的链接。 Describes the behavior that caused a <see cref="Scroll" /> event.
<see langword> 将指定文本的格式设置为代码。 Gets the value of the <see langword="Accept-Ranges" /> header for an HTTP response.
<seealso> 向指定的 API 添加“另请参阅”链接。 <seealso cref="T:System.Single" />
<typeparamref> 指代一个类型参数。 The <typeparamref name="THandler" /> is resolved from a scoped service provider.

有关详细信息,请参阅适用于 C# 和 C# 规范的建议 XML 标记ECMAXML 规范也有良好的信息,尽管请注意 ECMAXML 和 /// 文档注释之间存在一些差异(例如,cref 目标已完全扩展,并在 ECMAXML 中具有前缀)。

交叉引用

当您使用<see cref>标记链接到另一个API时,无需在类型名称前添加前缀,例如使用T:标记表示类型或M:标记表示方法。 事实上,代码分析 规则 CA1200 会标记在 cref 标签中为类型名称添加前缀的代码注释。 但是,此规则有几个例外:

  • 如果想要链接到具有多个重载的方法的一般形式,C# 编译器 当前不支持此形式。 文档的解决方法是在源代码(或 O: ECMAXML 中)为方法名称Overload:添加前缀,并取消规则 CA1200。 例如: <altmember cref="O:System.Diagnostics.Process.Kill" />
  • 当无法从当前上下文(包括任何 using 指令)解析 API 时。 在这种情况下,请使用具有前缀的完全限定 API 名称。

<see cref>将标记转换为 ECMAXML 时,mdoc 会将类型名称替换为 API 的完整 DocId,其中包括前缀。

说明

有关描述每个符号类型及其各个部分的权威指南,请参阅 .NET API 文档 wiki

空注释

空注释的已知占位符文本为 To be added.。 Learn 生成系统可识别此文本,并在 ECMAXML 转换为 HTML 时将其删除,留下空说明。

单独的代码文件

如果代码示例很长,则可以将其放在文档存储库中的单独文件中,并通过以下方式从源代码链接到该文件:

/// <example>
/// <format type="text/markdown">
/// <![CDATA[
///  [!code-csharp[FieldAware](~/docs/samples/Microsoft.ML.Samples/Dynamic/FactorizationMachine.cs)]
/// ]]></format>
/// </example>

有关如何连接单独的代码文件的更多详细信息,请参阅 此讨论

语言属性

标记上的 <code> 语言属性是可选的,但它们会导致代码使用颜色编码进行格式设置。 例如:

/// <example>
/// This sample shows the basic pattern for defining a typed client class.
///   <code language="csharp">
///     class ExampleClient
///     {
///       private readonly HttpClient _httpClient;
///       private readonly ILogger _logger;
///
///       // Typed clients can use constructor injection to access additional services.
///       public ExampleClient(HttpClient httpClient, ILogger&lt;ExampleClient&gt; logger)
///       {
///         _httpClient = httpClient;
///         _logger = logger;
///       }
///     }
///   </code>
/// </example>

内部 API

记录使用者不打算使用的 API 时,请使用类似于以下内容的措辞:

<summary>This type supports the .NET infrastructure and is not intended to be used directly from your code.</summary>

另请参阅