附件 D 文档注释
此附件提供了信息。
D.1 常规
C# 提供了一种让程序员使用包含 XML 文本的注释语法来记录其代码的机制。 在源代码文件中,具有特定格式的注释可用于指示工具从这些注释生成 XML,以及它们前面的源代码元素。 使用此类语法的注释称为 文档注释。 它们必须紧接在用户定义的类型(如类、委托或接口)或成员(如字段、事件、属性或方法)之前。 XML 生成工具称为文档生成器。 (此生成器可以是 C# 编译器本身,但不需要。文档生成器生成的输出称为文档文件。 文档文件用作文档查看器的输入;该工具旨在生成某种类型的信息及其关联文档的视觉显示。
不需要符合 C# 编译器来检查文档注释的语法;此类注释只是普通评论。 但是,允许符合要求的编译器进行此类检查。
此规范建议在文档注释中使用一组标准标记,但不需要使用这些标记,并且如果需要,只要遵循格式正确的 XML 规则,就可以使用其他标记。 对于面向 CLI 的 C# 实现,它还提供有关文档生成器和文档文件格式的信息。 没有提供有关文档查看器的信息。
D.2 简介
具有特定表单的注释可用于指示工具从这些注释及其前面的源代码元素生成 XML。 这些注释Single_Line_Comment s (§6.3.3) 以三个斜杠 (///
), 或以斜杠和两个星号 (§6.3.3) 开头的Delimited_Comments (/**
§6.3.3)。 它们必须紧接在用户定义类型或他们批注的成员之前。 属性部分(§22.3)被视为声明的一部分,因此文档注释必须在应用于类型或成员的属性之前。
出于公开目的,文档注释的格式如下所示,分为两个语法规则: Single_Line_Doc_Comment 和 Delimited_Doc_Comment。 但是,这些规则不是 C# 语法的一部分,而是分别表示Single_Line_Comment和Delimited_Comment词法规则的特定格式。
语法:
Single_Line_Doc_Comment
: '///' Input_Character*
;
Delimited_Doc_Comment
: '/**' Delimited_Comment_Section* ASTERISK+ '/'
;
在Single_Line_Doc_Comment中,如果在当前Single_Line_Doc_Comment相邻的每个Single_Line_Doc_Comments上有一个空格字符///
,则 XML 输出中不包含空格字符。
在Delimited_Doc_Comment中,如果第二行的第一个非空格字符是 ASTERISK,并且可选的空格字符模式相同,并且 ASTERISK 字符在Delimited_Doc_Comment内每行的开头重复,则重复模式的字符不会包含在 XML 输出中。 该模式可以包括空格字符之后和之前 ASTERISK 字符。
示例:
/// <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 格式不正确,将生成警告,文档文件将包含一条注释,指出遇到错误。
尽管开发人员可以自由创建自己的标记集,但建议的集在 §D.3 中定义。 部分建议标记具有特殊含义:
<param>
标记用于描述参数。 如果使用此类标记,文档生成器必须验证指定的参数是否存在,以及文档注释中是否描述了所有参数。 如果此类验证失败,文档生成器会发出警告。cref
属性可以附加到任何标记,以提供对代码元素的引用。 文档生成器必须验证此代码元素是否存在。 如果验证失败,文档生成器会发出警告。 在查找属性中描述的cref
名称时,文档生成器必须尊重命名空间可见性,具体取决于源代码中显示的 using 语句。 对于泛型代码元素,无法使用普通泛型语法(例如“”List<T>
),因为它生成无效的 XML。 大括号可以代替括号(例如;可以使用“”List{T}
或 XML 转义语法(例如,“List<T>
)。标记
<summary>
供文档查看器用来显示有关类型或成员的其他信息。该
<include>
标记包含来自外部 XML 文件的信息。
请注意,文档文件不提供有关类型和成员的完整信息(例如,它不包含任何类型信息)。 若要获取有关类型或成员的此类信息,文档文件必须与类型或成员的反射结合使用。
D.3 建议标记
D.3.1 常规
文档生成器必须接受并处理任何根据 XML 规则有效的标记。 下列标记提供用户文档中的常用功能。 (当然,其他标记是可能的。
标记 | 引用 | 用途 |
---|---|---|
<c> |
§D.3.2 | 在类似代码的字体中设置文本 |
<code> |
§D.3.3 | 设置一行或多行源代码或程序输出 |
<example> |
§D.3.4 | 指示示例 |
<exception> |
§D.3.5 | 标识方法可以引发的异常 |
<include> |
§D.3.6 | 包括外部文件中的 XML |
<list> |
§D.3.7 | 创建列表或表 |
<para> |
§D.3.8 | 允许将结构添加到文本 |
<param> |
§D.3.9 | 描述方法或构造函数的参数 |
<paramref> |
§D.3.10 | 确定单词是参数名称 |
<permission> |
§D.3.11 | 记录成员的安全辅助功能 |
<remarks> |
§D.3.12 | 描述有关类型的其他信息 |
<returns> |
§D.3.13 | 描述方法的返回值 |
<see> |
§D.3.14 | 指定链接 |
<seealso> |
§D.3.15 | 生成“另请参阅”条目 |
<summary> |
§D.3.16 | 描述类型或类型的成员 |
<typeparam> |
§D.3.17 | 描述泛型类型或方法的类型参数 |
<typeparamref> |
§D.3.18 | 确定单词是类型参数名称 |
<value> |
§D.3.19 | 描述属性 |
D.3.2 <c>
此标记提供一种机制,用于指示说明中的文本片段应以特殊字体(例如用于代码块)进行设置。 对于实际代码行,请使用 <code>
(§D.3.3)。
语法:
<c>
text</c>
示例:
/// <summary>
/// Class <c>Point</c> models a point in a two-dimensional plane.
/// </summary>
public class Point
{
}
D.3.3 <代码>
此标记用于以某种特殊字体设置一行或多行源代码或程序输出。 对于叙述中的小代码片段,请使用 <c>
(§D.3.2)。
语法:
<code>
源代码或程序输出</code>
示例:
public class Point
{
/// <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 dx, int dy)
{
...
}
}
D.3.4 <示例>
此标记允许注释中的示例代码指定如何使用方法或其他库成员。 通常,这也涉及使用标记 <code>
(§D.3.3)。
语法:
<example>
说明</example>
示例:
有关示例,请参阅 <code>
(§D.3.3)。
D.3.5 <异常>
此标记提供了一种方法来记录方法可以引发的异常。
语法:
<exception cref="
成员">
说明</exception>
where
cref="
成员"
是成员的名称。 文档生成器检查给定成员是否存在,并将成员转换为文档文件中的规范元素名称。- 说明 是引发异常的情况的说明。
示例:
class PrimaryFileFormatCorruptException : System.Exception { ... }
class PrimaryFileLockedOpenException : System.Exception { ... }
public class DataBaseOperations
{
/// <exception cref="PrimaryFileFormatCorruptException">
/// Thrown when the primary file is corrupted.
/// </exception>
/// <exception cref="PrimaryFileLockedOpenException">
/// Thrown when the primary file is already open.
/// </exception>
public static void ReadRecord(int flag)
{
if (flag == 1)
{
throw new PrimaryFileFormatCorruptException();
}
else if (flag == 2)
{
throw new PrimaryFileLockedOpenException();
}
...
}
}
D.3.6 <包括>
此标记允许包含来自源代码文件外部的 XML 文档的信息。 外部文件必须是格式正确的 XML 文档,并且 XPath 表达式应用于该文档,以指定要包含的文档中的 XML。 然后,该 <include>
标记将替换为外部文档中的选定 XML。
语法:
<include file="
filename" path="
xpath" />
where
file="
filename"
是外部 XML 文件的文件名。 文件名相对于包含包含标记的文件进行解释。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 strings.
</summary>
</class>
</extradoc>
然后,输出的文档与源代码包含的相同:
/// <summary>
/// Contains a list of integers.
/// </summary>
public class IntList { ... }
D.3.7 <列表>
此标记用于创建列表或项表。 它可以包含一个 <listheader>
块来定义表或定义列表的标题行。 (定义表时,只需提供标题中术语的条目。
列表中的每个项均使用 <item>
块指定。 创建定义列表时, 必须指定术语 和 说明 。 但是,对于表、项目符号列表或编号列表,只需 指定说明 。
语法:
<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>
where
- term 是要定义的术语,其定义在说明中。
- description 是项目符号或编号列表中的项,或术语的定义。
示例:
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()
{
...
}
}
D.3.8 <para>
此标记用于其他标记(如 <summary>
(§D.3.16)或 <returns>
(§D.3.13),并允许将结构添加到文本中。
语法:
<para>
content</para>
where
- 内容 是段落的文本。
示例:
public class Point
{
/// <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-trivial maintenance has
/// been performed on the Point class.
/// </para>
/// </summary>
public static void Main()
{
...
}
}
D.3.9 <参数>
此标记用于描述方法、构造函数或索引器的参数。
语法:
<param name="
name">
description</param>
where
- name 是参数的名称。
- description 是参数的说明。
示例:
public class Point
{
/// <summary>
/// This method changes the point's location to
/// the given coordinates.
/// </summary>
/// <param name="xPosition">the new x-coordinate.</param>
/// <param name="yPosition">the new y-coordinate.</param>
public void Move(int xPosition, int yPosition)
{
...
}
}
D.3.10 <paramref>
此标记用于指示单词是参数。 文档文件可以处理为此参数设置某种不同格式。
语法:
<paramref name="
name"/>
where
- name 是参数的名称。
示例:
public class Point
{
/// <summary>This constructor initializes the new Point to
/// (<paramref name="xPosition"/>,<paramref name="yPosition"/>).
/// </summary>
/// <param name="xPosition">the new Point's x-coordinate.</param>
/// <param name="yPosition">the new Point's y-coordinate.</param>
public Point(int xPosition, int yPosition)
{
...
}
}
D.3.11 <权限>
此标记允许记录成员的安全辅助功能。
语法:
<permission cref="
成员">
说明</permission>
where
- 成员 是成员的名称。 文档生成器检查给定的代码元素是否存在,并将成员转换为文档文件中的规范元素名称。
- 说明 是对成员的访问权限的说明。
示例:
public class MyClass
{
/// <permission cref="System.Security.PermissionSet">
/// Everyone can access this method.
/// </permission>
public static void Test()
{
...
}
}
D.3.12 <备注>
此标记用于指定有关类型的额外信息。 使用 <summary>
(§D.3.16) 描述类型本身和类型的成员。
语法:
<remarks>
说明</remarks>
where
- 说明 是备注的文本。
示例:
/// <summary>
/// Class <c>Point</c> models a point in a two-dimensional plane.
/// </summary>
/// <remarks>
/// Uses polar coordinates
/// </remarks>
public class Point
{
...
}
D.3.13 <返回>
此标记用于描述方法的返回值。
语法:
<returns>
说明</returns>
where
- description 是返回值的说明。
示例:
public class Point
{
/// <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() => $"({X},{Y})";
public int X { get; set; }
public int Y { get; set; }
}
D.3.14 <请参阅>
此标记允许在文本中指定链接。 使用 <seealso>
(§D.3.15) 指示显示在 “另见” 子文档中的文本。
语法:
<see cref="
成员" href="
URL" langword="
关键字" />
where
- 成员 是成员的名称。 文档生成器检查给定的代码元素是否存在,并将成员更改为生成的文档文件中的元素名称。
- url 是对外部源的引用。
- 俚语 是一个以某种方式突出显示的词。
示例:
public class Point
{
/// <summary>
/// This method changes the point's location to
/// the given coordinates. <see cref="Translate"/>
/// </summary>
public void Move(int xPosition, int yPosition)
{
...
}
/// <summary>This method changes the point's location by
/// the given x- and y-offsets. <see cref="Move"/>
/// </summary>
public void Translate(int dx, int dy)
{
...
}
}
D.3.15 <seealso>
此标记允许为 See Also 子引用生成条目。 使用 <see>
(§D.3.14) 指定文本中的链接。
语法:
<seealso cref="
成员" href="
URL" />
where
- 成员 是成员的名称。 文档生成器检查给定的代码元素是否存在,并将成员更改为生成的文档文件中的元素名称。
- url 是对外部源的引用。
示例:
public class Point
{
/// <summary>
/// This method determines whether two Points have the same location.
/// </summary>
/// <seealso cref="operator=="/>
/// <seealso cref="operator!="/>
public override bool Equals(object o)
{
...
}
}
D.3.16 <摘要>
此标记可用于描述类型的类型或成员。 使用 <remarks>
(§D.3.12) 指定有关类型或成员的额外信息。
语法:
<summary>
说明</summary>
where
- 说明 是类型或成员的摘要。
示例:
public class Point
{
/// <summary>
/// This constructor initializes the new Point to
/// (<paramref name="xPosition"/>,<paramref name="yPosition"/>).
/// </summary>
public Point(int xPosition, int yPosition)
{
...
}
/// <summary>This constructor initializes the new Point to (0,0).</summary>
public Point() : this(0, 0)
{
}
}
D.3.17 <typeparam>
此标记用于描述泛型类型或方法的类型参数。
语法:
<typeparam name="
name">
description</typeparam>
where
- name 是类型参数的名称。
- description 是类型参数的说明。
示例:
/// <summary>A generic list class.</summary>
/// <typeparam name="T">The type stored by the list.</typeparam>
public class MyList<T>
{
...
}
D.3.18 <typeparamref>
此标记用于指示单词是类型参数。 可以处理文档文件以某种不同的方式格式化此类型参数。
语法:
<typeparamref name="
name"/>
where
- name 是类型参数的名称。
示例:
public class MyClass
{
/// <summary>
/// This method fetches data and returns a list of
/// <typeparamref name="T"/>.
/// </summary>
/// <param name="query">query to execute</param>
public List<T> FetchData<T>(string query)
{
...
}
}
D.3.19 <值>
此标记允许描述属性。
语法:
<value>
属性说明</value>
where
- 属性说明 是属性的说明。
示例:
public class Point
{
/// <value>Property <c>X</c> represents the point's x-coordinate.</value>
public int X { get; set; }
}
D.4 处理文档文件
D.4.1 常规
以下信息适用于面向 CLI 的 C# 实现。
文档生成器为源代码中标记的文档注释中的每个元素生成 ID 字符串。 此 ID 字符串唯一标识源元素。 文档查看器可以使用 ID 字符串标识文档适用的相应项。
文档文件不是源代码的分层表示形式;相反,它是一个平面列表,其中包含每个元素生成的 ID 字符串。
D.4.2 ID 字符串格式
文档生成器在生成 ID 字符串时会遵循以下规则:
字符串不得包含空格。
字符串的第一部分通过单个字符后跟冒号标识要记录的成员类型。 定义了以下类型的成员:
字符 描述 E 事件 周五 字段 M 方法(包括构造函数、终结器和运算符) N 命名空间 P 属性(包括索引器) T 类型(如类、委托、枚举、接口和结构) ! 错误字符串;字符串的其余部分提供有关错误的信息。 例如,文档生成器为无法解决的链接生成错误信息。 字符串的第二部分是元素的完全限定名称,从命名空间的根目录开始。 元素的名称、其封闭类型(s)和命名空间由句点分隔。 如果项本身的名称有句点,则用 #(U+0023) 字符替换它们。 (假定没有元素在其名称中具有此字符。完全限定名称中的类型参数,用于当成员显式实现泛型接口的成员时,通过将“”和“”周围的“
<
和”“替换为”{
“和”>
“}
字符来编码。对于具有参数的方法和属性,参数列表后面括在括号中。 对于没有参数的那些,省略括号。 确保自变量之间用逗号分隔。 每个参数的编码与 CLI 签名相同,如下所示:
- 参数由其文档名称表示,该名称基于其完全限定的名称进行修改,如下所示:
- 表示泛型类型的参数具有追加的“
'
”字符,后跟类型参数的数目 - 具有
in
参数或out
ref
修饰符的参数具有以下@
类型名称。 按值传递或通过params
的参数没有特殊表示法。 - 作为数组的参数表示为
[
下限:
大小,
...,
lowerbound:
大小]
其中逗号数小于 1,每个维度的下限和大小(如果已知)以十进制表示。 如果未指定下限或大小,则省略它。 如果省略特定维度的下限和大小,则也会省略“:
”。 Jagged 数组由每个级别一个“”[]
表示。 当下限为 0(默认值)时,单维数组省略下限(默认值)(§17.1)。 - 具有指针类型以外的
void
参数,这些参数使用*
以下类型名称表示。 指针void
使用类型System.Void
名称表示 。 - 引用类型上定义的泛型类型参数的参数使用“
`
”字符进行编码,后跟类型参数的从零开始的索引。 - 使用方法中定义的泛型类型参数的参数使用双反杆“
``
”而不是用于类型的“`
”。 - 引用构造泛型类型的参数使用泛型类型进行编码,后跟“”
{
,后跟逗号分隔的类型参数列表,后跟“}
”。
- 表示泛型类型的参数具有追加的“
- 参数由其文档名称表示,该名称基于其完全限定的名称进行修改,如下所示:
D.4.3 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> { ... }
}
}
ID:
"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;
}
}
ID:
"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) { ... }
}
}
ID:
"M:Acme.Widget.#cctor"
"M:Acme.Widget.#ctor"
"M:Acme.Widget.#ctor(System.String)"
终结器
namespace Acme
{
class Widget : IProcess
{
~Widget() { ... }
}
}
ID:
"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, in int i) { ... }
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 value) { ... }
}
}
ID:
"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@,System.Int32@)"
"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``1(``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 { ... } }
}
}
ID:
"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;
}
}
ID:
"E:Acme.Widget.AnEvent"
一元运算符
namespace Acme
{
class Widget : IProcess
{
public static Widget operator+(Widget x) { ... }
}
}
ID:
"M:Acme.Widget.op_UnaryPlus(Acme.Widget)"
使用的一元运算符函数名称的完整集如下所示:op_UnaryPlus
、、、op_UnaryNegation
op_OnesComplement
op_LogicalNot
、op_Increment
、op_Decrement
、 op_True
和。op_False
二进制运算符
namespace Acme
{
class Widget : IProcess
{
public static Widget operator+(Widget x1, Widget x2) { ... }
}
}
ID:
"M:Acme.Widget.op_Addition(Acme.Widget,Acme.Widget)"
使用的二进制运算符函数名称的完整集如下所示:op_Addition
、、、op_Modulus
op_Division
op_BitwiseOr
op_ExclusiveOr
op_Subtraction
op_BitwiseAnd
op_Multiply
op_LeftShift
、、 op_Equality
op_RightShift
op_LessThan
op_LessThanOrEqual
op_Inequality
op_GreaterThan
和。op_GreaterThanOrEqual
转换运算符 具有尾随“~
”,后跟返回类型。 当转换运算符的源或目标是泛型类型时,“”<
和“”">
字符将分别替换为“{
”和“”字符}
。
namespace Acme
{
class Widget : IProcess
{
public static explicit operator int(Widget x) { ... }
public static implicit operator long(Widget x) { ... }
}
}
ID:
"M:Acme.Widget.op_Explicit(Acme.Widget)~System.Int32"
"M:Acme.Widget.op_Implicit(Acme.Widget)~System.Int64"
D.5 示例
D.5.1 C# 源代码
以下示例显示了 Point 类的源代码:
namespace Graphics
{
/// <summary>
/// Class <c>Point</c> models a point in a two-dimensional plane.
/// </summary>
public class Point
{
/// <value>
/// Property <c>X</c> represents the point's x-coordinate.
/// </value>
public int X { get; set; }
/// <value>
/// Property <c>Y</c> represents the point's y-coordinate.
/// </value>
public int Y { get; set; }
/// <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="xPosition"/>,<paramref name="yPosition"/>).
/// </summary>
/// <param name="xPosition">The new Point's x-coordinate.</param>
/// <param name="yPosition">The new Point's y-coordinate.</param>
public Point(int xPosition, int yPosition)
{
X = xPosition;
Y = yPosition;
}
/// <summary>
/// This method changes the point's location to
/// the given coordinates. <see cref="Translate"/>
/// </summary>
/// <param name="xPosition">The new x-coordinate.</param>
/// <param name="yPosition">The new y-coordinate.</param>
public void Move(int xPosition, int yPosition)
{
X = xPosition;
Y = yPosition;
}
/// <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).
/// <see cref="Move"/>
/// </example>
/// </summary>
/// <param name="dx">The relative x-offset.</param>
/// <param name="dy">The relative y-offset.</param>
public void Translate(int dx, int dy)
{
X += dx;
Y += dy;
}
/// <summary>
/// This method determines whether two Points have the same location.
/// </summary>
/// <param name="o">
/// 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 ((object)this == o)
{
return true;
}
if (GetType() == o.GetType())
{
Point p = (Point)o;
return (X == p.X) && (Y == p.Y);
}
return false;
}
/// <summary>
/// This method returns a Point's hashcode.
/// </summary>
/// <returns>
/// The int hashcode.
/// </returns>
public override int GetHashCode()
{
return X + (Y >> 4); // a crude version
}
/// <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() => $"({X},{Y})";
/// <summary>
/// This operator determines whether two Points have the same location.
/// </summary>
/// <param name="p1">The first Point to be compared.</param>
/// <param name="p2">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 name="p1">The first Point to be compared.</param>
/// <param name="p2">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) => !(p1 == p2);
}
}
D.5.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="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="xPosition"/>,<paramref name="yPosition"/>).
</summary>
<param name="xPosition">The new Point's x-coordinate.</param>
<param name="yPosition">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.
<see cref="M:Graphics.Point.Translate(System.Int32,System.Int32)"/>
</summary>
<param name="xPosition">The new x-coordinate.</param>
<param name="yPosition">The new y-coordinate.</param>
</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>
<see cref="M:Graphics.Point.Move(System.Int32,System.Int32)"/>
</summary>
<param name="dx">The relative x-offset.</param>
<param name="dy">The relative y-offset.</param>
</member>
<member name="M:Graphics.Point.Equals(System.Object)">
<summary>
This method determines whether two Points have the same location.
</summary>
<param name="o">
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 name="p1">The first Point to be compared.</param>
<param name="p2">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 name="p1">The first Point to be compared.</param>
<param name="p2">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-trivial 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>
信息性文本的结尾。