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 { }
您可以設定 GenerateDocumentationFile 或 DocumentationFile 選項,編譯程式會在原始程式碼中尋找具有 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 元素),您可以使用標準引用機制 (<
和 >
)。 若要參考程式代碼參考 (cref
) 元素中的泛型識別碼,您可以使用逸出字元 (例如 cref="List<T>"
) 或大括號 (cref="List{T}"
)。 就特殊情況而言,編譯程式會將大括弧剖析為角括弧,讓檔批注在參考泛型標識符時,對作者來說不那麼麻煩。
備註
如果您使用單行 XML 批註分隔符撰寫批註, ///
但不包含任何標記,編譯程式會將這些批註的文字新增至 XML 輸出檔。 不過,輸出不包含 XML 元素,例如 <summary>
。 大部分使用 XML 批注的工具(包括 Visual Studio IntelliSense)不會閱讀這些批注。
接受 XML 檔輸入的工具
下列工具會從 XML 註解產生輸出:
- DocFX: DocFX 是適用於 .NET 的 API 文件產生器,目前支援 C#、Visual Basic 和 F#。 它也可讓您自定義產生的參考檔。 DocFX 會從原始程式碼和 Markdown 檔案建置靜態 HTML 網站。 此外,DocFX 也可讓您彈性地透過範本自定義網站的版面配置和樣式。 您也可以建立自定義範本。
- Sandcastle: Sandcastle 工具 會為包含概念和 API 參考頁面的 Managed 類別庫建立說明檔案。 Sandcastle 工具是以命令行為基礎,沒有 GUI 前端、專案管理功能或自動化建置程式。 Sandcastle 說明檔產生器提供獨立 GUI 和命令行式工具,以自動化方式建置說明檔。 Visual Studio 整合套件也可供使用,以便完全從 Visual Studio 內建立和管理說明專案。
- Doxygen: Doxygen 會從一組記載的原始程式檔產生在線文件瀏覽器(HTML)或離線參考手冊(在 LaTeX 中)。 也支援在 RTF (MS Word)、PostScript、超連結 PDF、壓縮 HTML、DocBook 和 Unix 手動頁面中產生輸出。 您可以設定 Doxygen,從未記載的原始程式檔擷取程式代碼結構。
備註
XML 檔批註不是元數據;它們不會包含在編譯的元件中,因此無法透過反映存取它們。
識別字串
每個類型或成員都會儲存在輸出 XML 檔案中的元素中。 每個元素都有識別類型或成員的唯一標識符字串。 標識符字串必須考慮運算符、參數、傳回值、泛型類型參數、 ref
、 in
和 out
參數。 為了編碼所有這些潛在元素,編譯程式會遵循明確定義的規則來產生標識符字串。 處理 XML 檔案的程式會使用識別符字串來識別文件所應用的對應 .NET 元數據或反射項目。
編譯程式會在產生標識符字串時觀察下列規則:
字串中沒有空格符。
字串的第一個部分會使用單一字元來識別成員種類,後面接著冒號。 使用下列成員類型:
角色 成員類型 備註 N
命名空間 您無法將文件註釋新增至命名空間,但在支援的情況下,您可以參考命名空間。 T
類型 類型是類別、介面、結構、列舉或委派。 F
领域 P
財產 包含索引器或其他索引屬性。 M
方法 包含特殊方法,例如建構函式和運算元。 E
事件 !
錯誤字串 字串的其餘部分會提供錯誤的相關信息。 C# 編譯程式會產生無法解析的連結錯誤資訊。 字串的第二個部分是專案的完整名稱,從命名空間的根目錄開始。 項目的名稱、其封入型別和命名空間會以句號分隔。 如果專案本身的名稱有句點,則會以哈希符號 ('#'' 取代它們)。 文法假設沒有任何專案在其名稱中直接具有哈希符號。 例如,String 建構函式的完整名稱是 「System.String.#ctor」。。
對於屬性和方法,以括弧括住的參數清單如下。 如果沒有參數,就不會有括號。 參數會以逗號分隔。 每個參數的編碼方式會直接遵循在 .NET 簽章中編碼的方式(如需下列清單中所有 caps 元素的定義,請參閱 Microsoft.VisualStudio.CorDebugInterop.CorElementType ):
- 基底類型。 一般型別 (
ELEMENT_TYPE_CLASS
或ELEMENT_TYPE_VALUETYPE
) 會表示為型別的完整名稱。 - 內在型別(例如,
ELEMENT_TYPE_I4
、ELEMENT_TYPE_OBJECT
、ELEMENT_TYPE_STRING
、ELEMENT_TYPE_TYPEDBYREF
和ELEMENT_TYPE_VOID
)表示為對應完整型別的完整名稱格式。 例如,System.Int32
或System.TypedReference
。 -
ELEMENT_TYPE_PTR
在修改的類型之後,會以 『*』 表示。 -
ELEMENT_TYPE_BYREF
在修改的類型之後,會以 '@' 表示。 -
ELEMENT_TYPE_CMOD_OPT
會以 '!' 表示,並在修改的類型之後,顯示修飾詞類別的完整限定名稱。 -
ELEMENT_TYPE_SZARRAY
在陣列的元素類型之後,會以 “[]” 表示。 -
ELEMENT_TYPE_ARRAY
表示為 [下限:size
,下限:size
],其中逗號數目是排名 - 1,而每個維度的下限和大小,如果已知,則會以十進位表示。 如果未指定下限和大小,則會省略它們。 如果省略特定維度的下限和大小,也會省略 ':'。 例如,以 1 做為下限且未指定大小的二維陣列是 [1:,1:]。
- 基底類型。 一般型別 (
若僅為轉換運算子(
op_Implicit
和op_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:type
(signature)”,其中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# 語言規格 附錄。