Files
YooAsset/Assets/YooAsset/Docs/注释规范.md
2026-03-20 19:51:28 +08:00

9.4 KiB
Raw Blame History

.NET 注释规范

参考来源:Microsoft C# XML 文档注释 · 推荐的文档注释标签 · 框架设计准则

核心原则:公共 API 必须注释、说明意图而非复述代码、保持与代码同步


一、概述

C# 使用 XML 文档注释为代码提供结构化文档。编译器从 ///(三斜杠)注释中生成 XML 文件,供 IDE 智能提示和文档生成工具使用。


二、XML 注释标签

2.1 核心标签

标签 用途 适用场景
<summary> 简要描述类型或成员的功能 所有公共类型和成员
<param> 描述方法参数 方法、构造函数
<returns> 描述方法返回值 有返回值的方法
<exception> 说明可能抛出的异常 可能抛出异常的方法
<remarks> 补充说明,提供额外细节 需要详细解释的成员
<value> 描述属性所代表的值 属性

2.2 引用标签

标签 用途 示例
<see cref=""/> 行内引用其他类型或成员 <see cref="MyClass"/>
<seealso cref=""/> 在"另请参阅"区域添加引用 <seealso cref="OtherMethod"/>
<paramref name=""/> 引用参数名 <paramref name="count"/>
<typeparamref name=""/> 引用泛型类型参数名 <typeparamref name="T"/>

2.3 格式标签

标签 用途
<para> <remarks> 等标签内分段
<list> 创建列表或表格
<code> 多行代码示例
<c> 行内代码片段
<example> 包含使用示例

2.4 泛型与继承标签

标签 用途
<typeparam> 描述泛型类型参数
<inheritdoc/> 继承基类或接口的文档注释

三、注释范围要求

3.1 必须添加注释的成员

访问级别 要求
public 必须添加完整 XML 注释
protected 必须添加完整 XML 注释
internal 建议添加 XML 注释
private 仅在逻辑复杂时添加

3.2 各成员类型的注释要求

成员类型 必需标签 可选标签
类 / 结构 <summary> <remarks><typeparam>
接口 <summary> <remarks>
方法 <summary><param><returns> <exception><remarks><example>
构造函数 <summary><param> <exception>
属性 <summary> <value><exception>
事件 <summary> <remarks>
枚举类型 <summary>
枚举值 <summary>
委托 <summary><param><returns>

四、书写原则

4.1 <summary> 书写规范

✔️ 一句话说明"做什么",而非"怎么做"。

✔️第三人称动词开头。

✔️ 完整语句末尾建议使用句号,短语式描述可省略。

禁止重复方法名或参数类型中已表达的信息。

禁止以"这个方法"、"该类"等冗余前缀开头。

4.2 常见动词约定

成员类型 推荐开头动词
返回 bool 的方法 / 属性 "检查是否"、"判断是否"
获取类方法 "获取"、"查询"
设置类方法 "设置"、"更新"
创建类方法 "创建"、"构建"、"生成"
事件 "当……时触发"
构造函数 "创建 XXX 实例"XXX 为类型的中文描述)

4.3 <param> 书写规范

✔️ 描述参数的含义和用途

✔️ 说明有效范围和边界值(如为 null 时的行为、取值范围)。

✔️ 完整语句末尾建议使用句号,短语式描述可省略。

禁止仅重复参数名或类型名,如"url 参数"。

4.4 <returns> 书写规范

✔️ 说明返回值的含义

✔️ 说明特殊返回值的含义(如返回 null 表示未找到)。

4.5 <exception> 书写规范

✔️ 指定异常的具体类型cref 属性)。

✔️ 说明异常的触发条件

✔️ 使用 <paramref> 引用相关参数。


五、注释示例

5.1 类注释

/// <summary>
/// 资源包下载请求,负责管理单个资源包的下载生命周期。
/// </summary>
/// <remarks>
/// <para>支持断点续传和失败重试。</para>
/// <para>通过 <see cref="DownloadRetryController"/> 控制重试策略。</para>
/// </remarks>
public class BundleDownloadRequest
{
}

5.2 方法注释

/// <summary>
/// 从指定 URL 异步下载资源包并保存到本地磁盘。
/// </summary>
/// <param name="url">资源包的完整下载地址。</param>
/// <param name="savePath">本地保存的目标路径。</param>
/// <param name="timeout">超时时间0 表示不限制。</param>
/// <returns>下载结果,包含状态码和错误信息。</returns>
/// <exception cref="ArgumentNullException">
/// 当 <paramref name="url"/> 或 <paramref name="savePath"/> 为 <c>null</c> 时抛出。
/// </exception>
/// <exception cref="TimeoutException">当下载超过指定时间时抛出。</exception>
public async Task<DownloadResult> DownloadAsync(string url, string savePath, int timeout = 30)
{
}

5.3 属性注释

/// <summary>
/// 获取当前下载进度。
/// </summary>
/// <value>取值范围 0.0 ~ 1.0,其中 1.0 表示下载完成。</value>
public float Progress { get; private set; }

5.4 枚举注释

/// <summary>
/// 下载任务的运行状态。
/// </summary>
public enum DownloadStatus
{
    /// <summary>
    /// 等待中,尚未开始下载。
    /// </summary>
    Pending,

    /// <summary>
    /// 正在下载中。
    /// </summary>
    Downloading,

    /// <summary>
    /// 下载已完成。
    /// </summary>
    Completed,

    /// <summary>
    /// 下载失败。
    /// </summary>
    Failed
}

5.5 泛型类注释

/// <summary>
/// 通用对象池,提供对象的复用管理。
/// </summary>
/// <typeparam name="T">池化对象的类型,必须实现 <see cref="IDisposable"/>。</typeparam>
public class ObjectPool<T> where T : IDisposable
{
}

5.6 接口注释

/// <summary>
/// 定义下载请求的标准行为。
/// </summary>
public interface IDownloadRequest
{
    /// <summary>
    /// 获取请求的远程 URL。
    /// </summary>
    string URL { get; }

    /// <summary>
    /// 取消当前下载请求。
    /// </summary>
    void Abort();
}

5.7 使用 <inheritdoc/>

public class MyDownloadRequest : IDownloadRequest
{
    /// <inheritdoc/>
    public string URL { get; }

    /// <inheritdoc/>
    public void Abort()
    {
    }
}

5.8 使用 <example><code>

/// <summary>
/// 根据资源路径异步加载资源对象。
/// </summary>
/// <param name="assetPath">资源路径。</param>
/// <returns>资源操作句柄,加载失败时资源对象为 <c>null</c>。</returns>
/// <example>
/// 加载一个预制体:
/// <code>
/// var handle = package.LoadAssetAsync&lt;GameObject&gt;("Assets/Prefabs/Player.prefab");
/// await handle.Task;
/// var prefab = handle.AssetObject as GameObject;
/// </code>
/// </example>
public AssetHandle LoadAssetAsync<T>(string assetPath)
{
}

六、反面示例

6.1 冗余注释

// ❌ 差:重复方法签名中已有的信息
/// <summary>
/// 下载方法,参数是 url 和 savePath。
/// </summary>
public void Download(string url, string savePath) { }

// ✔️ 好:说明行为和目的
/// <summary>
/// 从远程服务器下载资源包并保存到本地磁盘。
/// </summary>
/// <param name="url">资源包的完整下载地址。</param>
/// <param name="savePath">本地保存的目标路径。</param>
public void Download(string url, string savePath) { }

6.2 废话参数注释

// ❌ 差:仅重复参数名
/// <param name="name">名称。</param>

// ✔️ 好:说明含义和约束
/// <param name="name">资源包的唯一标识名称,不可为 <c>null</c> 或空字符串。</param>

6.3 缺少边界说明

// ❌ 差:未说明返回 null 的情况
/// <returns>资源对象。</returns>

// ✔️ 好:说明特殊返回值
/// <returns>加载到的资源对象,如果资源不存在则返回 <c>null</c>。</returns>

七、行内注释规范

对于非 XML 文档注释(// 普通注释),遵循以下原则:

7.1 基本准则

✔️ 解释"为什么",而非"是什么"——代码本身应说明"做什么",注释解释不明显的意图或约束。

✔️ 标记待办事项使用 // TODO: 前缀。

✔️ 标记临时方案使用 // HACK: 前缀。

✔️ 修改代码时同步更新相关注释,过时的注释比没有注释更有害。

禁止注释显而易见的代码,如 // 递增计数器// 返回结果

禁止用注释替代清晰的命名——如果需要注释来解释变量含义,应优先改善变量名。

7.2 示例

// ❌ 差:复述代码
// 如果计数大于最大值,重置为零
if (count > maxCount)
    count = 0;

// ✔️ 好:解释约束
// 环形缓冲区写满后从头覆盖,避免无限增长
if (count > maxCount)
    count = 0;