一、Sandcastle
這個是c#類庫方法根據註釋生成幫助文件的工具,我們經常會遇到把DLL或者API提供給別人呼叫的情況,通過在方法中添加註釋,然後再用Sandcastle 來自動生成文件給呼叫者,如下圖:
圖1:這是Sandcastle Help File Builder軟體介面
圖2:這是生成的chm文件
還可以直接給出示例程式碼:
圖3:還可以直接生成網頁
二、下載安裝
下載地址:
Help File Builder and Tools v2021.4.9.0最新版本
下載連結:https://github.com/EWSoftware/SHFB/releases
單純Sandcastle好像是沒有介面的, 這個連結提供的下載可以包含圖形介面。
注意:如果需要生成chm還需要微軟的 MicrosoftHTMLHelpWorkshop 支援,Sandcastle生成時會自動去查詢MicrosoftHTMLHelpWorkshop 的安裝目錄。
安裝:
安裝很簡單,兩個軟體都只需要直接點選“下一步”即可安裝完成。
三、Sandcastle配置
安裝好軟體後可以根據自己的需要配置相應的引數。
預設情況下dll中所有方法和屬性都會生成對應文件,也可以根據自己需要只把DLL中需要的類或方法生成文件,可通過如下圖配置:
在左側把需要的類或方法勾選就行了:
在使用工具生成文件前,別忘了在VS中要作簡單配置,才能生成DLL對應的XML配置檔案,vs配置方法如下:
在VS中右鍵專案屬性:
把"XML documentation file:"勾選,當編譯時在生成DLL的同時還會生成一個和dll同名的xml配置檔案。
在Sandcastle中右側視窗右鍵將需要生成文件的dll和對應的xml新增進來:
點選工具欄上的
這個按鈕就可以自動生成文件了。
四、C#註釋規範
為了生成友好的幫助文件,註釋規範自然少不了,以下是關於C#的註釋規範以及各引數的說明,註釋越詳細,生成的文件可讀性越好:
1、C#註釋標記:
大家對註釋應該都不陌生,在方法或者類前面三個斜槓就自動添加了常用的註釋標記,如下圖:
但是如果想要得到更加友好的幫助文件,註釋得花點心思。
如文章開頭所展示的幫助文件,部分方法的註釋如下:
2、C#註釋標記說明:
A.2.1.
此標記提供一種機制以指示用特殊字型(如用於程式碼塊的字型)設定說明中的文字段落。對於實際程式碼行,請使用 (第 A.2.2 節)。
語法:
text
示例:
/// Class Point models a point in a two-dimensional
/// plane.public class Point
{
// ...
}A.2.2.
此標記用於將一行或多行原始碼或程式輸出設定為某種特殊字型。對於敘述中較小的程式碼段,請使用 (第 A.2.1 節)。
語法:
source code or program output
示例:
/// This method changes the point's location by
/// the given x- and y-offsets.
/// For example:
///
/// Point p = new Point(3,5);
/// p.Translate(-1,3);
///
/// results in p's having the value (2,8).
///
///public void Translate(int xor, int yor) {
X += xor;
Y += yor;
}A.2.3.
此標記用於在註釋中插入程式碼示例,以說明如何使用所關聯的方法或其他庫成員。通常,此標記是同標記 (第 A.2.2 節)一起使用的。
語法:
description
示例:
有關示例,請參見 (第 A.2.2 節)。
A.2.4.
此標記提供一種方法以說明關聯的方法可能引發的異常。
語法:
description
其中
cref="member"
成員的名稱。文件生成器檢查給定成員是否存在,並將 member 轉換為文件檔案中的規範元素名稱。
description
對引發異常的情況的描述。
示例:
public class DataBaseOperations
{
///
///
public static void ReadRecord(int flag) {
if (flag == 1)
throw new MasterFileFormatCorruptException();
else if (flag == 2)
throw new MasterFileLockedOpenException();
// …
}
}A.2.5.
此標記允許包含來自原始碼檔案外部的 XML 文件的資訊。外部檔案必須是符合標準格式的 XML 文件,還可以將 XPath 表示式應用於該文件來指定應包含該 XML 文件中的哪些 XML 文字。然後用從外部文件中選定的 XML 來替換 標記。
語法:
filename" path="xpath" />
其中
file="filename"
外部 XML 檔案的檔名。該檔名是相對於包含 include 標記的檔案進行解釋的(確定其完整路徑名)。
path="xpath"
XPath 表示式,用於選擇外部 XML 檔案中的某些 XML。
示例:
如果原始碼包含了如下宣告:
/// "docs.xml" path='extradoc/class[@name="IntList"]/*' />
public class IntList { … }並且外部檔案“docs.xml”含有以下內容:
"1.0"?>
"IntList">
Contains a list of integers.
"StringList">
Contains a list of integers.
這樣輸出的文件就與原始碼中包含以下內容時一樣:
///
/// Contains a list of integers.
///
public class IntList { … }A.2.6.
此標記用於建立列表或專案表。它可以包含 塊以定義表或定義列表的標頭行。(定義表時,僅需要在標頭中為 term 提供一個項。)
列表中的每一項都用一個 塊來描述。建立定義列表時,必須同時指定 term 和 description。但是,對於表、專案符號列表或編號列表,僅需要指定 description。
語法:
term
description
term
description
…
term
description其中
term
要定義的術語,其定義位於 description 中。
description
是專案符號列表或編號列表中的項,或者是 term 的定義。
示例:
public class MyClass
{
/// Here is an example of a bulleted list:
///
///
/// Item 1.
///
///
/// Item 2.
///
///
///
public static void Main () {
// ...
}
}A.2.7.
此標記用於其他標記內,如 (第 A.2.11 節)或 (第 A.2.12 節),用於將結構新增到文字中。
語法:
content
其中
content
段落文字。
示例:
/// This is the entry point of the Point class testing program.
/// This program tests each method and operator, and
/// is intended to be run after any non-trvial maintenance has
/// been performed on the Point class.
public static void Main() {
// ...
}A.2.8.
該標記用於描述方法、建構函式或索引器的引數。
語法:
description
其中
name
引數名。
description
引數的描述。
示例:
/// This method changes the point's location to
/// the given coordinates.
///the new x-coordinate.
///the new y-coordinate.
public void Move(int xor, int yor) {
X = xor;
Y = yor;
}A.2.9.
該標記表示某單詞是一個引數。這樣,生成文件檔案後經適當處理,可以用某種獨特的方法來格式化該引數。
語法:
name"/>
其中
name
引數名。
示例:
/// This constructor initializes the new Point to
/// (,).
///the new Point's x-coordinate.
///the new Point's y-coordinate.public Point(int xor, int yor) {
X = xor;
Y = yor;
}A.2.10.
該標記用於將成員的安全性和可訪問性記入文件。
語法:
description
其中
cref="member"
成員的名稱。文件生成器檢查給定的程式碼元素是否存在,並將 member 轉換為文件檔案中的規範化元素名稱。
description
對成員的訪問屬性的說明。
示例:
/// Everyone can
/// access this method.public static void Test() {
// ...
}A.2.11.
該標記用於指定型別的概述資訊。(使用 (第 A.2.15 節)描述型別的成員。)
語法:
description
其中
description
摘要文字。
示例:
/// Class Point models a point in a
/// two-dimensional plane.
public class Point
{
// ...
}A.2.12.
該標記用於描述方法的返回值。
語法:
description
其中
description
返回值的說明。
示例:
/// Report a point's location as a string.
/// A string representing a point's location, in the form (x,y),
/// without any leading, trailing, or embedded whitespace.
public override string ToString() {
return "(" + X + "," + Y + ")";
}A.2.13.
該標記用於在文字內指定連結。使用 (第 A.2.14 節)指示將在“請參見”部分中出現的
文字。語法:
member"/>
其中
cref="member"
成員的名稱。文件生成器檢查給定的程式碼元素是否存在,並將 member 更改為所生成的文件檔案中的元素名稱。
示例:
/// This method changes the point's location to
/// the given coordinates.
///
public void Move(int xor, int yor) {
X = xor;
Y = yor;
}/// This method changes the point's location by
/// the given x- and y-offsets.
///
///
public void Translate(int xor, int yor) {
X += xor;
Y += yor;
}A.2.14.
該標記用於生成將列入“請參見”部分的項。使用 (第 A.2.13 節)指定來自文字內的連結。
語法:
member"/>
其中
cref="member"
成員的名稱。文件生成器檢查給定的程式碼元素是否存在,並將 member 更改為所生成的文件檔案中的元素名稱。
示例:
/// This method determines whether two Points have the same
/// location.
///
///
public override bool Equals(object o) {
// ...
}A.2.15.
可以用此標記描述型別的成員。使用 (第 A.2.11 節)描述型別本身。
語法:
description
其中
description
關於成員的摘要描述。
示例:
/// This constructor initializes the new Point to (0,0).
public Point() : this(0,0) {
}A.2.16.
該標記用於描述屬性。
語法:
property description
其中
property description
屬性的說明。
示例:
/// Property X represents the point's x-coordinate.
public int X
{
get { return x; }
set { x = value; }
}A.3. 處理文件檔案
文件生成器為原始碼中每個附加了“文件註釋標記”的程式碼元素生成一個 ID 字串。該 ID 字串唯一地標識源元素。文件檢視器利用此 ID 字串來標識該文件所描述的對應的元資料/反射項。
文件檔案不是原始碼的層次化表現形式;而是為每個元素生成的 ID 字串的一維列表。
A.3.1. ID 字串格式
文件生成器在生成 ID 字串時遵循下列規則:
· 不在字串中放置空白。
· 字串的第一部分通過單個字元後跟一個冒號來標識被標識成員的種類。定義以下幾種成員:
字元
說明
E
事件
F
欄位
M
方法(包括建構函式、解構函式和運算子)
N
名稱空間
P
屬性(包括索引器)
T
型別(如類、委託、列舉、介面和結構)
!
錯誤字串;字串的其他部分提供有關錯誤的資訊。例如,文件生成器對無法解析的連結生成錯誤資訊。
· 字串的第二部分是元素的完全限定名,從名稱空間的根開始。元素的名稱、包含著它的型別和名稱空間都以句點分隔。如果項名本身含有句點,則將用 # (U+0023) 字元替換。(這裡假定所有元素名中都沒有“# (U+0023)”字元。)
· 對於帶有引數的方法和屬性,接著是用括號括起來的引數列表。對於那些不帶引數的方法和屬性,則省略括號。多個引數以逗號分隔。每個引數的編碼都與 CLI 簽名相同,如下所示:引數由其完全限定名來表示。例如,int 變成 System.Int32、string 變成 System.String、object 變成 System.Object 等。具有 out 或 ref 修飾符的引數在其型別名後跟有 @ 符。對於由值傳遞或通過 params 傳遞的引數沒有特殊表示法。陣列引數表示為 [ lowerbound : size , … , lowerbound : size ],其中逗號數量等於秩減去一,而下限和每個維的大小(如果已知)用十進位制數表示。如果未指定下限或大小,它將被省略。如果省略了某個特定維的下限及大小,則“:”也將被省略。交錯陣列由每個級別一個“[]”來表示。指標型別為非 void 的引數用型別名後面跟一個 * 的形式來表示。void 指標用型別名 System.Void 表示。
A.3.2. ID 字串示例
下列各個示例分別演示一段 C# 程式碼以及為每個可以含有文件註釋的源元素生成的 ID 字串:
· 型別用它們的完全限定名來表示。
enum Color { Red, Blue, Green }
namespace Acme
{
interface IProcess {...}struct ValueType {...}
class Widget: IProcess
{
public class NestedClass {...}public interface IMenuItem {...}
public delegate void Del(int i);
public enum Direction { North, South, East, West }
}
}"T:Color"
"T:Acme.IProcess"
"T:Acme.ValueType"
"T:Acme.Widget"
"T:Acme.Widget.NestedClass"
"T:Acme.Widget.IMenuItem"
"T:Acme.Widget.Del"
"T:Acme.Widget.Direction"· 欄位用它們的完全限定名來表示。
namespace Acme
{
struct ValueType
{
private int total;
}class Widget: IProcess
{
public class NestedClass
{
private int value;
}private string message;
private static Color defaultColor;
private const double PI = 3.14159;
protected readonly double monthlyAverage;
private long[] array1;
private Widget[,] array2;
private unsafe int *pCount;
private unsafe float **ppValues;
}
}"F:Acme.ValueType.total"
"F:Acme.Widget.NestedClass.value"
"F:Acme.Widget.message"
"F:Acme.Widget.defaultColor"
"F:Acme.Widget.PI"
"F:Acme.Widget.monthlyAverage"
"F:Acme.Widget.array1"
"F:Acme.Widget.array2"
"F:Acme.Widget.pCount"
"F:Acme.Widget.ppValues"· 建構函式。
namespace Acme
{
class Widget: IProcess
{
static Widget() {...}public Widget() {...}
public Widget(string s) {...}
}
}"M:Acme.Widget.#cctor"
"M:Acme.Widget.#ctor"
"M:Acme.Widget.#ctor(System.String)"· 解構函式。
namespace Acme
{
class Widget: IProcess
{
~Widget() {...}
}
}"M:Acme.Widget.Finalize"
· 方法。
namespace Acme
{
struct ValueType
{
public void M(int i) {...}
}class Widget: IProcess
{
public class NestedClass
{
public void M(int i) {...}
}public static void M0() {...}
public void M1(char c, out float f, ref ValueType v) {...}
public void M2(short[] x1, int[,] x2, long[][] x3) {...}
public void M3(long[][] x3, Widget[][,,] x4) {...}
public unsafe void M4(char *pc, Color **pf) {...}
public unsafe void M5(void *pv, double *[][,] pd) {...}
public void M6(int i, params object[] args) {...}
}
}"M:Acme.ValueType.M(System.Int32)"
"M:Acme.Widget.NestedClass.M(System.Int32)"
"M:Acme.Widget.M0"
"M:Acme.Widget.M1(System.Char,System.Single@,Acme.ValueType@)"
"M:Acme.Widget.M2(System.Int16[],System.Int32[0:,0:],System.Int64[][])"
"M:Acme.Widget.M3(System.Int64[][],Acme.Widget[0:,0:,0:][])"
"M:Acme.Widget.M4(System.Char*,Color**)"
"M:Acme.Widget.M5(System.Void*,System.Double*[0:,0:][])"
"M:Acme.Widget.M6(System.Int32,System.Object[])"· 屬性和索引器。
namespace Acme
{
class Widget: IProcess
{
public int Width { get {...} set {...} }
public int this[int i] { get {...} set {...} }
public int this[string s, int i] { get {...} set {...} }
}
}"P:Acme.Widget.Width"
"P:Acme.Widget.Item(System.Int32)"
"P:Acme.Widget.Item(System.String,System.Int32)"· 事件。
namespace Acme
{
class Widget: IProcess
{
public event Del AnEvent;
}
}"E:Acme.Widget.AnEvent"
· 一元運算子。
namespace Acme
{
class Widget: IProcess
{
public static Widget operator+(Widget x) {...}
}
}"M:Acme.Widget.op_UnaryPlus(Acme.Widget)"
下面列出可使用的一元運算子函式名稱的完整集合:op_UnaryPlus、op_UnaryNegation、op_LogicalNot、op_OnesComplement、op_Increment、op_Decrement、op_True 和 op_False。
· 二元運算子。
namespace Acme
{
class Widget: IProcess
{
public static Widget operator+(Widget x1, Widget x2) {...}
}
}"M:Acme.Widget.op_Addition(Acme.Widget,Acme.Widget)"
下面列出可使用的二元運算子函式名稱的完整集合:op_Addition、op_Subtraction、op_Multiply、op_Division、op_Modulus、op_BitwiseAnd、op_BitwiseOr、op_ExclusiveOr、op_LeftShift、op_RightShift、op_Equality、op_Inequality、op_LessThan、op_LessThanOrEqual、op_GreaterThan 和 op_GreaterThanOrEqual。
· 轉換運算子具有一個尾隨“~”,然後再跟返回型別。
namespace Acme
{
class Widget: IProcess
{
public static explicit operator int(Widget x) {...}
public static implicit operator long(Widget x) {...}
}
}"M:Acme.Widget.op_Explicit(Acme.Widget)~System.Int32"
"M:Acme.Widget.op_Implicit(Acme.Widget)~System.Int64"
好了,以上就是關於Sandcastle的使用,相信大家以後都可以用得上,同時也給自己留作備忘。
為了節省大家的時間,我把這一套軟體都放到某度網盤了,下載連結如下(永久有效):
連結:https://pan.baidu.com/s/1SElm0dMGUBTqab26Z1aSUw
提取碼:y4m1