Alen Liu

人生最重要的不是过得怎样,而是懂得怎样过。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一、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.Int32string 变成 System.Stringobject 变成 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_UnaryPlusop_UnaryNegationop_LogicalNotop_OnesComplementop_Incrementop_Decrementop_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_Additionop_Subtractionop_Multiplyop_Divisionop_Modulusop_BitwiseAndop_BitwiseOrop_ExclusiveOrop_LeftShiftop_RightShiftop_Equalityop_Inequalityop_LessThanop_LessThanOrEqualop_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

 

posted on 2021-08-14 14:13  Alen Liu  阅读(1898)  评论(3编辑  收藏  举报