A. 文档注释
C# 提供一种机制,使程序员可以使用含有 XML 文本的特殊注释语法为他们的代码编写文档。在源代码文件中,可以使用特定形式的注释来指导工具从这些注释及其后的源代码元素生成 XML。使用这类语法的注释称为文档注释 (documentation comment)。这些注释后面必须紧跟用户定义的类型(如类、委托或接口)或者成员(如字段、事件、属性或方法)。该 XML 生成工具称为文档生成器。 \t "See documentation comment" (此生成器可以但不需要是 C# 编译器本身。)文档生成器生成的输出称为文档文件。 \t "See documentation comment" \b 文档文件用作文档查看器( \t "See documentation comment" \b \b 一个用于生成类型信息及其关联文档的某种可视显示的工具)的输入。
此规范推荐了一组在文档注释中使用的标记,但是这些标记不是必须使用的,如果需要也可以使用其他标记,只要遵循“格式良好的 XML”规则即可。
A.1 介绍
具有特殊格式的注释可用于指导某个工具根据这些注释 和它们后面的源代码元素生成 XML。这类注释是以三个斜杠 (///) 开始的单行注释,或者是以一个斜杠和两个星号 /**) 开始的分隔注释。这些注释后面必须紧跟它们所注释的用户定义类型(如类、委托或接口)或者成员(如字段、事件、属性或方法)。特性节(第 17.2 节)被视为声明的一部分,因此,文档注释必须位于应用到类型或成员的特性之前。
语法:
single-line-doc-comment:
///
input-charactersopt
delimited-doc-comment:
/**
delimited-comment-textopt
*/
在 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 \b 特性可以附加到任意标记,以提供对代码元素的引用。文档生成器必须验证此代码元素是否存在。如果验证失败,文档生成器将发出警告。查找在 cref 特性中描述的名称时,文档生成器必须根据源代码中出现的 using 语句来考虑命名空间的可见性。对于泛型代码元素,不能使用正常的泛型语法(即“List<T>”),因为该语法会生成无效的 XML。可以使用大括号代替方括号(即“List{T}”),也可以使用 XML 转义语法(即“List<T>”)。
- <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 |
包括来自外部文件的 |
<list> |
A.2.6 |
创建列表或表 |
<para> |
A.2.7 |
用于将结构添加到文本中 |
<param> |
A.2.8 |
描述方法或构造函数的参数 |
<paramref> |
A.2.9 |
确认某个单词是参数名 |
<permission> |
A.2.10 |
描述成员的安全性和访问权限 |
<remark> |
A.2.11 |
描述有关类型的更多信息 |
<returns> |
A.2.12 |
描述方法的返回值 |
<see> |
A.2.13 |
指定链接 |
<seealso> |
A.2.14 |
生成“请参见”项 |
<summary> |
A.2.15 |
描述类型或类型的成员 |
<value> |
A.2.16 |
描述属性 |
<typeparam> |
描述泛型类型形参 |
|
<typeparamref> |
标识某个单词是类型形参名称 |
A.2.1 <c> \t "See <c>" \b
此标记提供一种机制以指示用特殊字体(如用于代码块的字体)设置说明中的文本段落。对于实际代码行,请使用 <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> \t "See <code>" \b
此标记用于将一行或多行源代码或程序输出设置为某种特殊字体。对于叙述中较小的代码段,请使用 <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> \t "See <example>" \b
此标记用于在注释中插入代码示例,以说明如何使用所关联的方法或其他库成员。通常,此标记是同标记 <code>(第 A.2.2 节)一起使用的。
语法:
<example>description</example>
示例:
有关示例,请参见 <code> (§A.2.2)。
A.2.4 <exception> \t "See <exception>" \b
此标记提供了一种用于记录方法可以引发的异常的方式。
语法:
<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> \t "See <list>"
\b
此标记用于创建项列表或项表。它可以包含 <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> \t "See <para>" \b
此标记用于其他标记内,如 <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> \t "See <param>" \b
该标记用于描述方法、构造函数或索引器的参数。
语法:
<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> \t "See <paramref>" \b
该标记表示某单词是一个参数。可以对生成文档文件进行处理,以便用某种独特的方法来设置该参数的格式。
语法:
<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> \t "See <permission>" \b
该标记用于将成员的安全性和可访问性记入文档。
语法:
<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 <remark> \t "See <remarks>" \b
该标记用于指定类型的额外信息。(使用 <summary>(第 A.2.15 节)描述类型本身及类型的成员。)
语法:
<remark>description</remark>
其中
description
备注文本。
示例:
///
<summary>Class <c>Point</c> models a point in a
/// two-dimensional plane.</summary>
/// <remark>Uses polar coordinates</remark>
public class Point
{
// ...
}
A.2.12 <returns> \t "See <returns>" \b
该标记用于描述方法的返回值。
语法:
<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> \t "See <see>" \b
此标记用于在文本内指定链接。(使用 <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> \t "See <seealso>" \b
该标记用于生成将列入“请参见”部分的项。(使用 <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> \t "See <summary>" \b
可以用此标记描述类型或类型的成员。使用 <remark>(第 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> \t "See <value>" \b
该标记用于描述属性。
语法:
<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.2.17 <typeparam>
该标记用于描述类、结构、接口、委托或方法的泛型类型参数。
语法:
<typeparam
name="name">description</typeparam>
其中
name
类型参数名。
description
类型参数的描述。
示例:
///
<summary>A generic list class.</summary>
/// <typeparam name="T">The type stored by the
list.</typeparam>
public class MyList<T> {
...
}
A.2.18 <typeparamref>
该标记表示某单词是一个类型参数。这样,生成文档文件后经适当处理,可以用某种独特的方法来格式化该类型参数。
语法:
<typeparamref
name="name"/>
其中
name
类型参数名。
示例:
/// <summary>This
method fetches data and returns a list of <typeparamref name=”T”>
”/>”> .</summary>
/// <param name="string">query to execute</param>
public List<T> FetchData<T>(string query) {
...
}
A.3 处理文档文件
文档生成器会为源代码中标记有文档注释的每个元素生成一个 ID 字符串。该 ID 字符串唯一地标识源元素。文档查看器利用此 ID 字符串来标识该文档所描述的对应的元数据/反射项。
文档文件不是源代码的层次化表现形式;而是为每个元素生成的 ID 字符串的一维列表。
A.3.1 ID 字符串格式
文档生成器在生成 ID 字符串时遵循下列规则:
- 不在字符串中放置空白。
- 字符串的第一部分通过单个字符后跟一个冒号来标识所记录的成员的种类。定义以下几种成员:
字符 |
说明 |
E |
事件 |
F |
字段 |
M |
方法(包括构造函数、析构函数和运算符) |
N |
命名空间 |
P |
属性(包括索引器) |
T |
类型(如类、委托、枚举、接口和结构) |
! |
错误字符串;字符串的其他部分提供有关错误的信息。例如,文档生成器对无法解析的链接生成错误信息。 |
- 字符串的第二部分是元素的完全限定名,从命名空间的根开始。元素的名称、其封闭类型和命名空间都以句点分隔。如果项名本身含有句点,则将用 # (U+0023)
字符替换。(假定任何元素的名称内都不包含此字符。) - 对于带有参数的方法和属性,接下来是用括号括起来的参数列表。对于那些不带参数的方法和属性,则省略括号。多个参数以逗号分隔。每个参数的编码都与 CLI 签名相同,如下所示:
- 参数由其基于完全限定名的文档名称来表示,并做如下修改:
表示泛型类型的实参附加了一个“’”字符,后接类型形参个数
具有 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 }
}
class MyList<T>
{
class Helper<U,V> {...}
}
}
"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"
”T:Acme.MyList`1”
”T:Acme.MyList`1.Helper`2”
- 字段用它们的完全限定名来表示:
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) {...}
}
class MyList<T>
{
public void Test(T t) { }
}
class UseList
{
public void Process(MyList<int>
list) { }
public MyList<T>
GetValues<T>(T inputValue) { return null; }
}
}
"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[])"
”M:Acme.MyList`1.Test(`0)”
”M:Acme.UseList.Process(Acme.MyList{System.Int32})”
”M:Acme.UseList.GetValues``(``0)”
- 属性和索引器。
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"
A.4 示例
A.4.1 C# 源代码
下面的示例演示一个 Point 类的源代码:
namespace
Graphics
{
/// <summary>Class <c>Point</c> models a point in a
two-dimensional plane.
/// </summary>
public class Point
{
/// <summary>Instance variable
<c>x</c> represents the point's
/// x-coordinate.</summary>
private int x;
/// <summary>Instance variable
<c>y</c> represents the point's
/// y-coordinate.</summary>
private int y;
/// <value>Property <c>X</c>
represents the point's x-coordinate.</value>
public int X
{
get { return x; }
set { x = value; }
}
/// <value>Property <c>Y</c>
represents the point's y-coordinate.</value>
public int Y
{
get { return y; }
set { y = value; }
}
/// <summary>This constructor initializes
the new Point to
/// (0,0).</summary>
public Point() : this(0,0) {}
/// <summary>This constructor initializes
the new Point to
/// (<paramref
name="xor"/>,<paramref
name="yor"/>).</summary>
/// <param><c>xor</c>
is the new Point's x-coordinate.</param>
/// <param><c>yor</c>
is the new Point's y-coordinate.</param>
public Point(int xor, int yor) {
X = xor;
Y = yor;
}
/// <summary>This method changes the
point's location to
/// the
given coordinates.</summary>
/// <param><c>xor</c>
is the new x-coordinate.</param>
/// <param><c>yor</c>
is the new y-coordinate.</param>
/// <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.
/// <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>
/// <param><c>xor</c>
is the relative x-offset.</param>
/// <param><c>yor</c>
is the relative y-offset.</param>
/// <see cref="Move"/>
public void Translate(int xor, int yor) {
X += xor;
Y += yor;
}
/// <summary>This method determines
whether two Points have the same
/// location.</summary>
/// <param><c>o</c> is
the object to be compared to the current object.
/// </param>
/// <returns>True if the Points
have the same location and they have
/// the
exact same type; otherwise, false.</returns>
/// <seealso
cref="operator=="/>
/// <seealso
cref="operator!="/>
public override bool Equals(object o) {
if (o == null) {
return false;
}
if (this == o) {
return true;
}
if (GetType() == o.GetType()) {
Point p = (Point)o;
return (X == p.X) && (Y ==
p.Y);
}
return false;
}
/// <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, training, or embedded whitespace.</returns>
public override string ToString() {
return "(" + X +
"," + Y + ")";
}
/// <summary>This operator determines
whether two Points have the same
/// location.</summary>
/// <param><c>p1</c> is
the first Point to be compared.</param>
/// <param><c>p2</c> is
the second Point to be compared.</param>
/// <returns>True if the Points
have the same location and they have
/// the
exact same type; otherwise, false.</returns>
/// <seealso
cref="Equals"/>
/// <seealso cref="operator!="/>
public static bool operator==(Point p1,
Point p2) {
if ((object)p1 == null || (object)p2
== null) {
return false;
}
if (p1.GetType() == p2.GetType()) {
return (p1.X == p2.X) &&
(p1.Y == p2.Y);
}
return false;
}
/// <summary>This operator determines
whether two Points have the same
/// location.</summary>
/// <param><c>p1</c> is
the first Point to be compared.</param>
/// <param><c>p2</c> is
the second Point to be compared.</param>
/// <returns>True if the Points do
not have the same location and the
/// exact
same type; otherwise, false.</returns>
/// <seealso
cref="Equals"/>
/// <seealso
cref="operator=="/>
public static bool operator!=(Point p1,
Point p2) {
return !(p1 == p2);
}
/// <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() {
// class test code goes here
}
}
}
A.4.2 生成的 XML
以下是文档生成器根据给定类 Point 的源代码(如上所示)所产生的输出:
<?xml
version="1.0"?>
<doc>
<assembly>
<name>Point</name>
</assembly>
<members>
<member name="T:Graphics.Point">
<summary>Class
<c>Point</c> models a point in a two-dimensional
plane.
</summary>
</member>
<member
name="F:Graphics.Point.x">
<summary>Instance
variable <c>x</c> represents the point's
x-coordinate.</summary>
</member>
<member
name="F:Graphics.Point.y">
<summary>Instance
variable <c>y</c> represents the point's
y-coordinate.</summary>
</member>
<member name="M:Graphics.Point.#ctor">
<summary>This
constructor initializes the new Point to
(0,0).</summary>
</member>
<member
name="M:Graphics.Point.#ctor(System.Int32,System.Int32)">
<summary>This
constructor initializes the new Point to
(<paramref
name="xor"/>,<paramref
name="yor"/>).</summary>
<param><c>xor</c> is the new Point's
x-coordinate.</param>
<param><c>yor</c> is the new Point's
y-coordinate.</param>
</member>
<member
name="M:Graphics.Point.Move(System.Int32,System.Int32)">
<summary>This method
changes the point's location to
the given
coordinates.</summary>
<param><c>xor</c> is the new
x-coordinate.</param>
<param><c>yor</c>
is the new y-coordinate.</param>
<see
cref="M:Graphics.Point.Translate(System.Int32,System.Int32)"/>
</member>
<member
name="M:Graphics.Point.Translate(System.Int32,System.Int32)">
<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>
<param><c>xor</c> is the relative
x-offset.</param>
<param><c>yor</c> is the relative
y-offset.</param>
<see
cref="M:Graphics.Point.Move(System.Int32,System.Int32)"/>
</member>
<member
name="M:Graphics.Point.Equals(System.Object)">
<summary>This method
determines whether two Points have the same
location.</summary>
<param><c>o</c> is the object to be compared to the
current
object.
</param>
<returns>True if the
Points have the same location and they have
the exact same type;
otherwise, false.</returns>
<seealso
cref="M:Graphics.Point.op_Equality(Graphics.Point,Graphics.Point)"/>
<seealso
cref="M:Graphics.Point.op_Inequality(Graphics.Point,Graphics.Point)"/>
</member>
<member
name="M:Graphics.Point.ToString">
<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,
training, or embedded whitespace.</returns>
</member>
<member
name="M:Graphics.Point.op_Equality(Graphics.Point,Graphics.Point)">
<summary>This operator
determines whether two Points have the
same
location.</summary>
<param><c>p1</c> is the first Point to be
compared.</param>
<param><c>p2</c> is the
second Point to be compared.</param>
<returns>True if the
Points have the same location and they have
the exact same type;
otherwise, false.</returns>
<seealso
cref="M:Graphics.Point.Equals(System.Object)"/>
<seealso
cref="M:Graphics.Point.op_Inequality(Graphics.Point,Graphics.Point)"/>
</member>
<member
name="M:Graphics.Point.op_Inequality(Graphics.Point,Graphics.Point)">
<summary>This operator
determines whether two Points have the
same
location.</summary>
<param><c>p1</c> is the first Point to be
compared.</param>
<param><c>p2</c> is the second Point to be
compared.</param>
<returns>True if the
Points do not have the same location and
the
exact same type; otherwise,
false.</returns>
<seealso
cref="M:Graphics.Point.Equals(System.Object)"/>
<seealso
cref="M:Graphics.Point.op_Equality(Graphics.Point,Graphics.Point)"/>
</member>
<member
name="M:Graphics.Point.Main">
<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>
</member>
<member
name="P:Graphics.Point.X">
<value>Property
<c>X</c> represents the point's
x-coordinate.</value>
</member>
<member
name="P:Graphics.Point.Y">
<value>Property
<c>Y</c> represents the point's
y-coordinate.</value>
</member>
</members>
</doc>