C# 提供一种机制,使程序员可以使用含有 XML 文本的特殊注释语法为他们的代码编写文档。在源代码文件中,具有某种格式的注释可用于指导某个工具根据这些注释和它们后面的源代码元素生成 XML。使用这类语法的注释称为文档注释 (documentation comment)。这些注释后面必须紧跟用户定义类型(如类、委托或接口)或者成员(如字段、事件、属性或方法)。XML 生成工具称作文档生成器 (documentation generator)。(此生成器可以但不一定必须是 C# 编译器本身。)由文档生成器产生的输出称为文档文件 (documentation file)。文档文件可作为文档查看器 (documentation viewer) 的输入;文档查看器是用于生成类型信息及其关联文档的某种可视化显示的工具。
此规范推荐了一组在文档注释中使用的标记,但是这些标记不是必须使用的,如果需要也可以使用其他标记,只要遵循“符合格式标准的 XML”规则即可。
A.1. 介绍
具有特殊格式的注释可用于指导某个工具根据这些注释和它们后面的源代码元素生成 XML。这类注释是以三个斜杠 (///) 开始的单行注释,或者是以一个斜杠和两个星号 (/**) 开始的分隔注释。这些注释后面必须紧跟它们所注释的用户定义类型(如类、委托或接口)或者成员(如字段、事件、属性或方法)。属性节(第 17.2 节)被视为声明的一部分,因此,文档注释必须位于应用到类型或成员的属性之前。
语法:
single-line-doc-comment:
/// input-charactersopt
delimited-doc-comment:
/** delimited-comment-charactersopt */
在 single-line-doc-comment 中,如果当前 single-line-doc-comment 旁边的每个 single-line-doc-comment 上的 /// 字符后跟有 whitespace 字符,则此 whitespace 字符不包括在 XML 输出中。
在 delimited-doc-comment 中,如果第二行上的第一个非 whitespace 字符是一个 asterisk,并且在 delimited-doc-comment 内的每行开头都重复同一个由可选 whitespace 字符和 asterisk 字符组成的样式,则该重复出现的样式所含的字符不包括在 XML 输出中。此样式中,可以在 asterisk 字符之前或之后包括 whitespace 字符。
示例:
/// <summary>Class <c>Point</c> models a point in a two-dimensional
/// plane.</summary>
///
public class Point
{
/// <summary>method <c>draw</c> renders the point.</summary>
void draw() {…}
}
文档注释内的文本必须根据 XML 规则 (http://www.w3.org/TR/REC-xml) 设置正确的格式。如果 XML 不符合标准格式,将生成警告,并且文档文件将包含一条注释,指出遇到错误。
尽管开发人员可自由创建它们自己的标记集,但第 A.2 节定义有建议的标记集。某些建议的标记具有特殊含义:
• <param> 标记用于描述参数。如果使用这样的标记,文档生成器必须验证指定参数是否存在以及文档注释中是否描述了所有参数。如果此验证失败,文档生成器将发出警告。
• cref 属性可以附加到任意标记,以提供对代码元素的参考。文档生成器必须验证此代码元素是否存在。如果验证失败,文档生成器将发出警告。查找在 cref 属性中描述的名称时,文档生成器必须根据源代码中出现的 using 语句来考虑命名空间的可见性。
• <summary> 标记旨在标出可由文档查看器显示的有关类型或成员的额外信息。
• <include> 标记表示应该包含的来自外部 XML 文件的信息。
注意,文档文件并不提供有关类型和成员的完整信息(例如,它不包含任何关于类型的信息)。若要获得有关类型或成员的完整信息,必须协同使用文档文件与对实际涉及的类型或成员的反射调用。
A.2. 建议的标记
文档生成器必须接受和处理任何根据 XML 规则有效的标记。下列标记提供了用户文档中常用的功能。(当然,也可能有其他标记。)
标记 章节 用途
<c> A.2.1
将文本设置为类似代码的字体
<code> A.2.2
将一行或多行源代码或程序输出设置为某种字体
<example> A.2.3
表示所含的是示例
<exception> A.2.4
标识方法可能引发的异常
<include> A.2.5
包括来自外部文件的 XML
<list> A.2.6
创建列表或表
<para> A.2.7
用于将结构添加到文本中
<param> A.2.8
描述方法或构造函数的参数
<paramref> A.2.9
确认某个单词是参数名
<permission> A.2.10
描述成员的安全性和访问权限
<summary> A.2.11
描述一种类型
<returns> A.2.12
描述方法的返回值
<see> A.2.13
指定链接
<seealso> A.2.14
生成“请参见”项
<summary> A.2.15
描述类型的成员
<value> A.2.16
描述属性
A.2.1. <c>
此标记提供一种机制以指示用特殊字体(如用于代码块的字体)设置说明中的文本段落。对于实际代码行,请使用 <code>(第 A.2.2 节)。
语法:
<c>text</c>
示例:
/// <summary>Class <c>Point</c> models a point in a two-dimensional
/// plane.</summary>
public class Point
{
// ...
}
A.2.2. <code>
此标记用于将一行或多行源代码或程序输出设置为某种特殊字体。对于叙述中较小的代码段,请使用 <c>(第 A.2.1 节)。
语法:
<code>source code or program output</code>
示例:
/// <summary>This method changes the point's location by
/// the given x- and y-offsets.
/// <example>For example:
/// <code>
/// Point p = new Point(3,5);
/// p.Translate(-1,3);
/// </code>
/// results in <c>p</c>'s having the value (2,8).
/// </example>
/// </summary>
public void Translate(int xor, int yor) {
X += xor;
Y += yor;
}
A.2.3. <example>
此标记用于在注释中插入代码示例,以说明如何使用所关联的方法或其他库成员。通常,此标记是同标记 <code>(第 A.2.2 节)一起使用的。
语法:
<example>description</example>
示例:
有关示例,请参见 <code>(第 A.2.2 节)。
A.2.4. <exception>
此标记提供一种方法以说明关联的方法可能引发的异常。
语法:
<exception cref="member">description</exception>
其中
cref="member"
成员的名称。文档生成器检查给定成员是否存在,并将 member 转换为文档文件中的规范元素名称。
description
对引发异常的情况的描述。
示例:
public class DataBaseOperations
{
/// <exception cref="MasterFileFormatCorruptException"></exception>
/// <exception cref="MasterFileLockedOpenException"></exception>
public static void ReadRecord(int flag) {
if (flag == 1)
throw new MasterFileFormatCorruptException();
else if (flag == 2)
throw new MasterFileLockedOpenException();
// …
}
}
A.2.5. <include>
此标记允许包含来自源代码文件外部的 XML 文档的信息。外部文件必须是符合标准格式的 XML 文档,还可以将 XPath 表达式应用于该文档来指定应包含该 XML 文档中的哪些 XML 文本。然后用从外部文档中选定的 XML 来替换 <include>标记。
语法:
<include file="filename" path="xpath" />
其中
file="filename"
外部 XML 文件的文件名。该文件名是相对于包含 include 标记的文件进行解释的(确定其完整路径名)。
path="xpath"
XPath 表达式,用于选择外部 XML 文件中的某些 XML。
示例:
如果源代码包含了如下声明:
/// <include file="docs.xml" path='extradoc/class[@name="IntList"]/*' />
public class IntList { … }
并且外部文件“docs.xml”含有以下内容:
<?xml version="1.0"?>
<extradoc>
<class name="IntList">
<summary>
Contains a list of integers.
</summary>
</class>
<class name="StringList">
<summary>
Contains a list of integers.
</summary>
</class>
</extradoc>
这样输出的文档就与源代码中包含以下内容时一样:
/// <summary>
/// Contains a list of integers.
/// </summary>
public class IntList { … }
A.2.6. <list>
此标记用于创建列表或项目表。它可以包含 <listheader> 块以定义表或定义列表的标头行。(定义表时,仅需要在标头中为 term 提供一个项。)
列表中的每一项都用一个 <item> 块来描述。创建定义列表时,必须同时指定 term 和 description。但是,对于表、项目符号列表或编号列表,仅需要指定 description。
语法:
<list type="bullet" | "number" | "table">
<listheader>
<term>term</term>
<description>description</description>
</listheader>
<item>
<term>term</term>
<description>description</description>
</item>
…
<item>
<term>term</term>
<description>description</description>
</item>
</list>
其中
term
要定义的术语,其定义位于 description 中。
description
是项目符号列表或编号列表中的项,或者是 term 的定义。
示例:
public class MyClass
{
/// <summary>Here is an example of a bulleted list:
/// <list type="bullet">
/// <item>
/// <description>Item 1.</description>
/// </item>
/// <item>
/// <description>Item 2.</description>
/// </item>
/// </list>
/// </summary>
public static void Main () {
// ...
}
}
A.2.7. <para>
此标记用于其他标记内,如 <summary>(第 A.2.11 节)或 <returns>(第 A.2.12 节),用于将结构添加到文本中。
语法:
<para>content</para>
其中
content
段落文本。
示例:
/// <summary>This is the entry point of the Point class testing program.
/// <para>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.</para></summary>
public static void Main() {
// ...
}
A.2.8. <param>
该标记用于描述方法、构造函数或索引器的参数。
语法:
<param name="name">description</param>
其中
name
参数名。
description
参数的描述。
示例:
/// <summary>This method changes the point's location to
/// the given coordinates.</summary>
/// <param name="xor">the new x-coordinate.</param>
/// <param name="yor">the new y-coordinate.</param>
public void Move(int xor, int yor) {
X = xor;
Y = yor;
}
A.2.9. <paramref>
该标记表示某单词是一个参数。这样,生成文档文件后经适当处理,可以用某种独特的方法来格式化该参数。
语法:
<paramref name="name"/>
其中
name
参数名。
示例:
/// <summary>This constructor initializes the new Point to
/// (<paramref name="xor"/>,<paramref name="yor"/>).</summary>
/// <param name="xor">the new Point's x-coordinate.</param>
/// <param name="yor">the new Point's y-coordinate.</param>
public Point(int xor, int yor) {
X = xor;
Y = yor;
}
A.2.10. <permission>
该标记用于将成员的安全性和可访问性记入文档。
语法:
<permission cref="member">description</permission>
其中
cref="member"
成员的名称。文档生成器检查给定的代码元素是否存在,并将 member 转换为文档文件中的规范化元素名称。
description
对成员的访问属性的说明。
示例:
/// <permission cref="System.Security.PermissionSet">Everyone can
/// access this method.</permission>
public static void Test() {
// ...
}
A.2.11. <summary>
该标记用于指定类型的概述信息。(使用 <summary>(第 A.2.15 节)描述类型的成员。)
语法:
<summary>description</summary>
其中
description
摘要文本。
示例:
/// <summary>Class <c>Point</c> models a point in a
/// two-dimensional plane.</summary>
public class Point
{
// ...
}
A.2.12. <returns>
该标记用于描述方法的返回值。
语法:
<returns>description</returns>
其中
description
返回值的说明。
示例:
/// <summary>Report a point's location as a string.</summary>
/// <returns>A string representing a point's location, in the form (x,y),
/// without any leading, trailing, or embedded whitespace.</returns>
public override string ToString() {
return "(" + X + "," + Y + ")";
}
A.2.13. <see>
该标记用于在文本内指定链接。使用 <seealso>(第 A.2.14 节)指示将在“请参见”部分中出现的
文本。
语法:
<see cref="member"/>
其中
cref="member"
成员的名称。文档生成器检查给定的代码元素是否存在,并将 member 更改为所生成的文档文件中的元素名称。
示例:
/// <summary>This method changes the point's location to
/// the given coordinates.</summary>
/// <see cref="Translate"/>
public void Move(int xor, int yor) {
X = xor;
Y = yor;
}
/// <summary>This method changes the point's location by
/// the given x- and y-offsets.
/// </summary>
/// <see cref="Move"/>
public void Translate(int xor, int yor) {
X += xor;
Y += yor;
}
A.2.14. <seealso>
该标记用于生成将列入“请参见”部分的项。使用 <see>(第 A.2.13 节)指定来自文本内的链接。
语法:
<seealso cref="member"/>
其中
cref="member"
成员的名称。文档生成器检查给定的代码元素是否存在,并将 member 更改为所生成的文档文件中的元素名称。
示例:
/// <summary>This method determines whether two Points have the same
/// location.</summary>
/// <seealso cref="operator=="/>
/// <seealso cref="operator!="/>
public override bool Equals(object o) {
// ...
}
A.2.15. <summary>
可以用此标记描述类型的成员。使用 <summary>(第 A.2.11 节)描述类型本身。
语法:
<summary>description</summary>
其中
description
关于成员的摘要描述。
示例:
/// <summary>This constructor initializes the new Point to (0,0).</summary>
public Point() : this(0,0) {
}
A.2.16. <value>
该标记用于描述属性。
语法:
<value>property description</value>
其中
property description
属性的说明。
示例:
/// <value>Property <c>X</c> represents the point's x-coordinate.</value>
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"
相关推荐
### C#文档注释规范详解 #### 一、引言 C#作为一种广泛使用的编程语言,不仅因其简洁高效的语法而受到开发者的喜爱,更重要的是它有一套完整的文档注释规范,帮助开发者更好地理解和维护代码。本文将深入探讨C#中...
### C#文档注释规范详解 #### 一、引言 C#作为一种广泛使用的面向对象编程语言,在软件开发过程中有着举足轻重的地位。为了提高代码的可读性和可维护性,C#提供了文档注释功能,使得程序员可以通过特定的XML格式...
"vs c# 文档注释 生成 源码"这个主题涉及到的是如何在VS中生成和管理C#项目的文档注释。首先,我们需要在项目设置中启用XML文档生成。这通常是在项目属性的“生成”选项卡下,勾选“输出XML文档”这一项。这样,在...
### C#命名与注释规范详解 #### 一、引言 在软件开发过程中,良好的命名规范和注释习惯能够显著提升代码的可读性和维护性。本文将围绕《C#命名与注释规范——个人版》进行深入解读,帮助读者理解和掌握C#中的命名...
本文档旨在定义一套完整的C#开发注释规范,涵盖注释的内容、格式以及适用场景,帮助开发者遵循统一的标准,提升代码质量。 ### 1. 概述 注释是代码中用于解释功能、逻辑或设计决策的文字,它为其他开发者理解和...
三、C# 文档注释规范 1. 创建注释:/// <summary>/// 创建注释/// 创建标识:汤晓磊20070416/// 方法描述:按照行政区划编码,查询出符合条件的人员编码/// 使用的表:/// 使用的视图:/// 使用的存储过程:/// ...
- 方法或函数应包含XML文档注释,方便自动生成API文档。 #### 六、空白与缩进规范 **6.1 术语** - 空白包括空格、制表符等。 **6.2 缩进对齐的要求** - 代码块内的语句应统一使用4个空格进行缩进。 **6.3 换行...
3. **XML注释**:使用`///`生成XML文档注释,这有助于自动生成API文档,例如: ```csharp /// /// 打开文件并返回流对象 /// /// 要打开的文件路径 /// 文件的Stream对象 public Stream OpenFile(string ...
文档注释用于描述程序中的类型、成员等,可以通过文档工具生成形式化的文档。 一个简单的“Hello,World”程序可以作为学习C#的起点。这个程序通常存储在一个扩展名为.cs的C#源文件中,并且可以用命令行编译器编译成...
对于类、方法和属性,应有文档注释(XML注释),以便自动生成API文档。类注释应概述其功能和用途;类属性注释应解释其作用和可能的值;方法注释应包含输入参数、返回值和可能抛出的异常信息;代码间注释用于解释非...
1. **注释规范**: - 注释应清晰、简洁,描述代码的目的和行为,而不是复述代码。 - 使用 XML 注释为类、方法和属性提供文档摘要,便于自动生成文档和 Intellisense。 1. **声明规范**: - 变量和参数应尽可能早...
C#语言规范是这种语言的一套官方文档,它详细描述了C#语言的所有方面,包括语法、语义、关键字、类型系统、特性、和程序设计模型等。 2. 文档的版本和修改: 本文件提到了版本5.0,并指出该版本的文档已经被转换为...
规范建议在每个类、方法、属性等定义之前添加文档注释,使用三重斜杠(`///`)来创建XML注释,这些注释可以被工具如Visual Studio自动生成帮助文档。 2. **命名约定**:C#的命名规则强调一致性,以提高代码的可读性...
2. **XML文档注释**:使用XML文档注释来生成API文档,提高代码的可维护性。 - 示例:`/// 获取学生信息</summary>` 3. **注释更新**:确保注释与代码同步更新,避免出现过时的注释。 ##### 3.4 代码结构 1. **...
4. **文档注释支持**:支持C#的XML文档注释(`///`),这种注释可以自动生成API文档。 5. **集成开发环境(IDE)插件**:许多注释检查工具会作为Visual Studio或Visual Studio Code等IDE的插件,提供实时的反馈,...
**C#编程规范文档详细解读** C#编程规范是一套旨在提高代码可读性、可维护性和团队协作效率的准则。这份文档详细规定了代码的编写格式、命名约定、注释标准以及语句结构等多个方面,是每个C#开发者应该遵循的指导...
C#语言的基础结构包括词法结构、基本概念、类型系统、变量、转换、表达式、语句、命名空间、类、结构体、数组、接口、枚举、委托、异常处理、特性、不安全代码和文档注释等。C#强调类型安全,禁止从未初始化变量中...
- **模块(类)注释**:每个类或模块应有文档注释,解释其功能、用途和主要方法。 - **类属性注释**:每个属性的上方应有注释,描述其作用、默认值及可能的副作用。 - **方法注释**:详细解释方法的功能、参数、...