文件註解
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> */
基於兩個原因,編譯器在下列註解中找不到任何模式。 首先,星號前面的空格數目不一致。 其次,第五行的開頭是 Tab,這與空白字元不符。 會將第二行到第五行的所有文字都處理為註解的一部分。
/** * <summary> * text * text2 * </summary> */
若要參考 XML 項目,例如,您的函式處理要在 XML 文件註解中描述的特定 XML 項目,您可以使用標準引號機制 (<
和 >
)。 若要參照程式碼參考 (cref
) 項目中的泛型識別碼,您可以使用逸出字元 (例如 cref="List<T>"
) 或大括號 (cref="List{T}"
)。 視為特殊案例的情形是,編譯器將大括號剖析為角括號,如此在參考泛型識別項時,文件註解撰寫起來就變得不那麼複雜。
注意
XML 文件註解並不是中繼資料,這些註解不會包含在編譯的組件內,因此不能透過反映存取。
接受 XML 文件輸入的工具
下列工具會從 XML 註解建立輸出:
- DocFX:DocFX 是 .NET 的 API 文件產生器,目前支援 C#、Visual Basic 和 F#。 其也可讓您自訂產生的參考文件。 DocFX 會從原始程式碼和 Markdown 檔案建置靜態 HTML 網站。 此外,DocFX 可讓您彈性地透過範本自訂網站的配置和樣式。 您還可以建立自訂範本。
- Sandcastle:Sandcastle 工具會為包含概念和 API 參考頁面的受控類別庫建立說明檔案。 Sandcastle 工具是以命令列為基礎,沒有 GUI 前端、專案管理功能或自動化建置處理序。 Sandcastle 說明檔案產生器提供獨立 GUI 和命令列式工具,以自動化方式建置說明檔案。 Visual Studio 整合套件也可供使用,以便從 Visual Studio 內完整建立和管理說明專案。
- Doxygen:Doxygen 會從一組記載的來源檔案產生線上文件瀏覽器 (在 HTML),或離線參考手冊 (在 LaTeX 中)。 也支援在 RTF (MS Word)、PostScript、超連結 PDF、壓縮 HTML、DocBook 和 Unix 手冊頁產生輸出。 您可以設定 Doxygen,從未記載的來源檔案中擷取程式碼結構。
識別碼字串
每個型別或成員都會儲存在輸出 XML 檔案的元素中。 每個元素都有可識別型別或成員的唯一識別碼字串。 識別碼字串必須考慮運算子、參數、傳回值、泛型型別參數、ref
、in
和 out
參數。 為了編碼所有這些潛在元素,編譯器會遵循明確定義的規則來產生識別碼字串。 處理 XML 檔案的程式可以使用識別碼字串,來識別適用於該文件的對應 .NET 中繼資料或反映項目。
編譯器在產生識別碼字串時會遵守下列規則:
字串中沒有空白字元。
識別碼字串的第一個部分會識別成員種類,格式為單一字元後面接著一個冒號。 使用的成員類型如下:
字元 成員類型 備註 N
命名空間 您無法將文件註解新增至命名空間,但可讓 cref 參考這些項目 (如果支援)。 T
type 型別是類別、介面、結構、列舉或委派。 F
field P
property 包含索引子或其他索引屬性。 M
method 包含特殊方法,例如建構函式和運算子。 E
event !
錯誤字串 字串的其餘部分提供與錯誤相關的資訊。 C# 編譯器會針對無法解析的連結產生錯誤資訊。 字串的第二個部分是項目的完整名稱 (從命名空間的根開始)。 項目名稱、其封入類型及命名空間會以句號來分隔。 如果項目名稱本身包含句點,則會以雜湊符號 ('#') 來加以取代。 假設沒有項目的名稱中直接含有雜湊符號。 例如,String 建構函式的完整名稱會是 "System.String.#ctor"。
對於屬性和方法,以括弧括住的參數清單如下。 如果沒有任何參數,就不會出現括弧。 以逗號分隔參數。 每個參數的編碼會直接遵循在 .NET 簽章中編碼的方式 (請參閱 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
會表示為 [lower bound:size
,lower bound: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
是傳回型別,而 signature 是方法的引數。 如果沒有任何引數,就會省略括弧。 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# 語言規格附錄。