共用方式為


產生 XML API 文件註解

C# 來源檔案可以包含結構化批注,這些批注會針對這些檔案中定義的類型產生 API 檔。 C# 編譯程式會產生 XML 檔案,其中包含代表批注和 API 簽章的結構化數據。 例如,其他工具可以處理 XML 輸出,以網頁或 PDF 檔案的形式建立人類可讀取的檔。

此程式提供許多優點,可讓您在程式代碼中新增 API 檔:

  • C# 編譯程式會將 C# 程式代碼的結構與批註的文字結合成單一 XML 檔。
  • C# 編譯程式會驗證批註是否符合相關標籤的 API 簽章。
  • 處理 XML 檔檔的工具可以定義這些工具特有的 XML 元素和屬性。

Visual Studio 之類的工具可為檔批注中使用的許多常見 XML 元素提供 IntelliSense。

本文涵蓋下列主題:

  • 檔註注和 XML 檔案產生
  • C# 編譯程式和 Visual Studio 驗證的標籤
  • 產生的 XML 檔案格式

建立 XML 檔案輸出

您藉由撰寫以三斜線標示的特殊註解區塊來建立程式碼的文件。 批註欄位包含 XML 元素,可描述批註後面的程式代碼區塊。 例如:

/// <summary>
/// This class performs an important function.
/// </summary>
public class MyClass { }

您可以設定 GenerateDocumentationFileDocumentationFile 選項,編譯程式會在原始程式碼中尋找具有 XML 標籤的所有批註字段,並從這些批註建立 XML 檔檔。 啟用此選項時,編譯程式會針對專案中宣告的任何公開可見成員產生 CS1591 警告,而不需要 XML 檔批注。

XML 批註格式

XML 檔批注的使用需要分隔符,以指出檔批注開始和結束的位置。 您可以使用下列分隔符搭配 XML 文件標記:

  • /// 單行分隔符:文件範例和 C# 專案範本會使用這種格式。 如果空格元遵循分隔符,則不會包含在 XML 輸出中。

    備註

    當您在程式代碼編輯器中輸入///分隔符之後,Visual Studio 會自動插入 <summary></summary> 標記,並將游標放在這些標籤。 您可以在 [ 選項] 對話框中開啟或關閉此功能。

  • /** */ 多行分隔符: /** */ 分隔符具有下列格式規則:
    • 在包含 /** 分隔符的行上,如果行的其餘部分是空格符,則不會針對批注處理該行。 如果分隔符後面的 /** 第一個字元是空格符,則會忽略該空格符,並處理該行的其餘部分。 否則,分隔符 /** 之後,該行的整個文本會被當作批注的一部分處理。

    • 在包含 */ 分隔符的那一行中,如果到 */ 分隔符之前只有空白,那麼該行將被忽略。 否則,行至 */ 分隔符的文字會處理為批注的一部分。

    • 針對以分隔符開頭 /** 的行之後的行,編譯程式會在每一行的開頭尋找一般模式。 此模式可以包含選擇性空格符和/或星號 (*),後面接著更選擇性的空格符。 如果編譯程式在每一行開頭或結尾找到不以 /***/ 分隔符開頭或結尾的常見模式,它將忽略這些行的該模式。

    • 只有以下評論中以 <summary> 開頭的行會被處理。 這三種標記格式會產生相同的批註。

      /** <summary>text</summary> */
      
      /**
      <summary>text</summary>
      */
      
      /**
      * <summary>text</summary>
      */
      
    • 編譯程式會識別第二行和第三行開頭的一般模式 “ * ”。 模式不會包含在輸出中。

      /**
      * <summary>
      * text </summary>*/
      
    • 編譯程式在下列批注中找不到常見的模式,因為第三行的第二個字元不是星號。 第二行和第三行上的所有文字都會處理為批注的一部分。

      /**
      * <summary>
         text </summary>
      */
      
    • 編譯程式在下列批注中找不到模式,原因有兩個。 首先,星號之前的空格數目不一致。 第二,第五行的開頭是索引標籤,這與空格不符。 第二行到五行的所有文字都會作為批注進行處理。

      /**
        * <summary>
        * text
      *  text2
       	*  </summary>
      */
      

若要參考 XML 元素(例如,您的函式會處理您想要在 XML 檔批註中描述的特定 XML 元素),您可以使用標準引用機制 (&lt;&gt;)。 若要參考程式代碼參考 (cref) 元素中的泛型識別碼,您可以使用逸出字元 (例如 cref="List&lt;T&gt;") 或大括號 (cref="List{T}")。 就特殊情況而言,編譯程式會將大括弧剖析為角括弧,讓檔批注在參考泛型標識符時,對作者來說不那麼麻煩。

備註

如果您使用單行 XML 批註分隔符撰寫批註, ///但不包含任何標記,編譯程式會將這些批註的文字新增至 XML 輸出檔。 不過,輸出不包含 XML 元素,例如 <summary>。 大部分使用 XML 批注的工具(包括 Visual Studio IntelliSense)不會閱讀這些批注。

接受 XML 檔輸入的工具

下列工具會從 XML 註解產生輸出:

  • DocFXDocFX 是適用於 .NET 的 API 文件產生器,目前支援 C#、Visual Basic 和 F#。 它也可讓您自定義產生的參考檔。 DocFX 會從原始程式碼和 Markdown 檔案建置靜態 HTML 網站。 此外,DocFX 也可讓您彈性地透過範本自定義網站的版面配置和樣式。 您也可以建立自定義範本。
  • SandcastleSandcastle 工具 會為包含概念和 API 參考頁面的 Managed 類別庫建立說明檔案。 Sandcastle 工具是以命令行為基礎,沒有 GUI 前端、專案管理功能或自動化建置程式。 Sandcastle 說明檔產生器提供獨立 GUI 和命令行式工具,以自動化方式建置說明檔。 Visual Studio 整合套件也可供使用,以便完全從 Visual Studio 內建立和管理說明專案。
  • DoxygenDoxygen 會從一組記載的原始程式檔產生在線文件瀏覽器(HTML)或離線參考手冊(在 LaTeX 中)。 也支援在 RTF (MS Word)、PostScript、超連結 PDF、壓縮 HTML、DocBook 和 Unix 手動頁面中產生輸出。 您可以設定 Doxygen,從未記載的原始程式檔擷取程式代碼結構。

備註

XML 檔批註不是元數據;它們不會包含在編譯的元件中,因此無法透過反映存取它們。

識別字串

每個類型或成員都會儲存在輸出 XML 檔案中的元素中。 每個元素都有識別類型或成員的唯一標識符字串。 標識符字串必須考慮運算符、參數、傳回值、泛型類型參數、 refinout 參數。 為了編碼所有這些潛在元素,編譯程式會遵循明確定義的規則來產生標識符字串。 處理 XML 檔案的程式會使用識別符字串來識別文件所應用的對應 .NET 元數據或反射項目。

編譯程式會在產生標識符字串時觀察下列規則:

  • 字串中沒有空格符。

  • 字串的第一個部分會使用單一字元來識別成員種類,後面接著冒號。 使用下列成員類型:

    角色 成員類型 備註
    N 命名空間 您無法將文件註釋新增至命名空間,但在支援的情況下,您可以參考命名空間。
    T 類型 類型是類別、介面、結構、列舉或委派。
    F 领域
    P 財產 包含索引器或其他索引屬性。
    M 方法 包含特殊方法,例如建構函式和運算元。
    E 事件
    ! 錯誤字串 字串的其餘部分會提供錯誤的相關信息。 C# 編譯程式會產生無法解析的連結錯誤資訊。
  • 字串的第二個部分是專案的完整名稱,從命名空間的根目錄開始。 項目的名稱、其封入型別和命名空間會以句號分隔。 如果專案本身的名稱有句點,則會以哈希符號 ('#'' 取代它們)。 文法假設沒有任何專案在其名稱中直接具有哈希符號。 例如,String 建構函式的完整名稱是 「System.String.#ctor」。。

  • 對於屬性和方法,以括弧括住的參數清單如下。 如果沒有參數,就不會有括號。 參數會以逗號分隔。 每個參數的編碼方式會直接遵循在 .NET 簽章中編碼的方式(如需下列清單中所有 caps 元素的定義,請參閱 Microsoft.VisualStudio.CorDebugInterop.CorElementType ):

    • 基底類型。 一般型別 (ELEMENT_TYPE_CLASSELEMENT_TYPE_VALUETYPE) 會表示為型別的完整名稱。
    • 內在型別(例如,ELEMENT_TYPE_I4ELEMENT_TYPE_OBJECTELEMENT_TYPE_STRINGELEMENT_TYPE_TYPEDBYREFELEMENT_TYPE_VOID)表示為對應完整型別的完整名稱格式。 例如,System.Int32System.TypedReference
    • ELEMENT_TYPE_PTR 在修改的類型之後,會以 『*』 表示。
    • ELEMENT_TYPE_BYREF 在修改的類型之後,會以 '@' 表示。
    • ELEMENT_TYPE_CMOD_OPT 會以 '!' 表示,並在修改的類型之後,顯示修飾詞類別的完整限定名稱。
    • ELEMENT_TYPE_SZARRAY 在陣列的元素類型之後,會以 “[]” 表示。
    • ELEMENT_TYPE_ARRAY 表示為 [下限size下限size],其中逗號數目是排名 - 1,而每個維度的下限和大小,如果已知,則會以十進位表示。 如果未指定下限和大小,則會省略它們。 如果省略特定維度的下限和大小,也會省略 ':'。 例如,以 1 做為下限且未指定大小的二維陣列是 [1:,1:]。
  • 若僅為轉換運算子(op_Implicitop_Explicit),方法的返回值會被編碼為 ~ 並接著返回型別。 例如:<member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32">System.Decimal 類別中宣告的轉換運算子 public static explicit operator int (decimal value); 的標記。

  • 針對泛型類型,類型的名稱後面接著一個反引號,然後是表示泛型參數數目的數字。 例如: <member name="T:SampleClass`2"> 是定義為 public class SampleClass<T, U>之型別的標記。 對於採用泛型型別做為參數的方法,泛型型別參數會指定為前面加上反引號的數位(例如 '0,'1)。 每個數位都代表類型泛型參數以零起始的陣列表示法。

    • ELEMENT_TYPE_PINNED 在修改的類型之後,會以 '^' 表示。 C# 編譯程式永遠不會產生此編碼。
    • ELEMENT_TYPE_CMOD_REQ 在修改的類型之後,會以 『|』 和修飾詞類別的完整名稱表示。 C# 編譯程式永遠不會產生此編碼。
    • ELEMENT_TYPE_GENERICARRAY 在陣列的元素類型之後,會以 “[?]” 表示。 C# 編譯程式永遠不會產生此編碼。
    • ELEMENT_TYPE_FNPTR 表示為 “=FUNC:typesignature)”,其中 type 是傳回型別, 而簽章 是 方法的自變數。 如果沒有參數,則會省略括號。 C# 編譯程式永遠不會產生此編碼。
    • 不會表示下列簽章元件,因為它們不會用來區分多載方法:
      • 呼叫慣例
      • 傳回類型
      • ELEMENT_TYPE_SENTINEL

下列範例示範如何產生類別及其成員的標識符字串:

namespace MyNamespace;

/// <summary>
/// Enter description here for class X.
/// ID string generated is "T:MyNamespace.MyClass".
/// </summary>
public unsafe class MyClass
{
    /// <summary>
    /// Enter description here for the first constructor.
    /// ID string generated is "M:MyNamespace.MyClass.#ctor".
    /// </summary>
    public MyClass() { }

    /// <summary>
    /// Enter description here for the second constructor.
    /// ID string generated is "M:MyNamespace.MyClass.#ctor(System.Int32)".
    /// </summary>
    /// <param name="i">Describe parameter.</param>
    public MyClass(int i) { }

    /// <summary>
    /// Enter description here for field Message.
    /// ID string generated is "F:MyNamespace.MyClass.Message".
    /// </summary>
    public string? Message;

    /// <summary>
    /// Enter description for constant PI.
    /// ID string generated is "F:MyNamespace.MyClass.PI".
    /// </summary>
    public const double PI = 3.14;

    /// <summary>
    /// Enter description for method Func.
    /// ID string generated is "M:MyNamespace.MyClass.Func".
    /// </summary>
    /// <returns>Describe return value.</returns>
    public int Func() => 1;

    /// <summary>
    /// Enter description for method SomeMethod.
    /// ID string generated is "M:MyNamespace.MyClass.SomeMethod(System.String,System.Int32@,System.Void*)".
    /// </summary>
    /// <param name="str">Describe parameter.</param>
    /// <param name="num">Describe parameter.</param>
    /// <param name="ptr">Describe parameter.</param>
    /// <returns>Describe return value.</returns>
    public int SomeMethod(string str, ref int num, void* ptr) { return 1; }

    /// <summary>
    /// Enter description for method AnotherMethod.
    /// ID string generated is "M:MyNamespace.MyClass.AnotherMethod(System.Int16[],System.Int32[0:,0:])".
    /// </summary>
    /// <param name="array1">Describe parameter.</param>
    /// <param name="array">Describe parameter.</param>
    /// <returns>Describe return value.</returns>
    public int AnotherMethod(short[] array1, int[,] array) { return 0; }

    /// <summary>
    /// Enter description for operator.
    /// ID string generated is "M:MyNamespace.MyClass.op_Addition(MyNamespace.MyClass,MyNamespace.MyClass)".
    /// </summary>
    /// <param name="first">Describe parameter.</param>
    /// <param name="second">Describe parameter.</param>
    /// <returns>Describe return value.</returns>
    public static MyClass operator +(MyClass first, MyClass second) { return first; }

    /// <summary>
    /// Enter description for property.
    /// ID string generated is "P:MyNamespace.MyClass.Prop".
    /// </summary>
    public int Prop { get { return 1; } set { } }

    /// <summary>
    /// Enter description for event.
    /// ID string generated is "E:MyNamespace.MyClass.OnHappened".
    /// </summary>
    public event Del? OnHappened;

    /// <summary>
    /// Enter description for index.
    /// ID string generated is "P:MyNamespace.MyClass.Item(System.String)".
    /// </summary>
    /// <param name="str">Describe parameter.</param>
    /// <returns></returns>
    public int this[string s] => 1;

    /// <summary>
    /// Enter description for class Nested.
    /// ID string generated is "T:MyNamespace.MyClass.Nested".
    /// </summary>
    public class Nested { }

    /// <summary>
    /// Enter description for delegate.
    /// ID string generated is "T:MyNamespace.MyClass.Del".
    /// </summary>
    /// <param name="i">Describe parameter.</param>
    public delegate void Del(int i);

    /// <summary>
    /// Enter description for operator.
    /// ID string generated is "M:MyNamespace.MyClass.op_Explicit(MyNamespace.MyClass)~System.Int32".
    /// </summary>
    /// <param name="myParameter">Describe parameter.</param>
    /// <returns>Describe return value.</returns>
    public static explicit operator int(MyClass myParameter) => 1;
}

C# 語言規格

如需詳細資訊,請參閱檔批注的 C# 語言規格 附錄。