· для методов и свойств с аргументами следует список аргументов, заключенный в круглые скобки. Если аргументов нет, скобки опускаются. Аргументы разделяются запятыми. Кодирование каждого аргумента такое же, как у подписи CLI, заключается в следующем:
o аргументы представлены своими именами в документации, основанными на их полном имени, со следующими изменениями:
к аргументам, представляющим универсальные типы, присоединяется символ «’», за которым следует число параметров типа;
у аргументов с модификатором out или ref за именем типа следует @. Аргументы, передаваемые по значению или через params, не имеют специального обозначения;
аргументы, являющиеся массивами, представляются как [ нижняя_граница: размер, …, нижняя_граница: размер ], где число запятых равно рангу минус один, а нижние границы и размер каждого измерения, если они известны, представляются десятичными числами. Если нижняя граница или размер не указаны, они опускаются. Если для отдельного измерения опущены и нижняя граница, и размер, то «:» тоже опускается. Массивы массивов представлены одним «[]» на каждый уровень:
аргументы, имеющие типы указателей, отличные от void, представляются с помощью * вслед за именем типа. Указатель типа void представляется с помощью имени типа System.Void;
аргументы, ссылающиеся на параметры универсального типа, определенные для типов, кодируются с помощью символа «`», за которым следует начинающийся с нуля индекс параметра типа;
аргументы, использующие параметры универсального типа, определенные в методах, используют двойной обратный апостроф «``» вместо одинарного «`», используемого для типов;
аргументы, ссылающиеся на построенные универсальные типы, кодируются с помощью универсального типа, за которым следует «{», затем разделенный запятыми список аргументов типа и затем «}».
A.3.2 Примеры строк идентификаторов
В каждом из следующих примеров показан фрагмент кода на C# вместе со строками идентификаторов, созданных по каждому исходному элементу, для которого возможен комментарий к документации:
· типы представлены своими полными именами, дополненными общими сведениями:
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>Класс <c>Point</c> моделирует точку на двумерной плоскости.
/// </summary>
public class Point
{
/// <summary>Переменная экземпляра <c>x</c> представляет
/// координату x точки.</summary>
private int x;
/// <summary>Переменная экземпляра <c>y</c> представляет
/// координату y точки.</summary>
private int y;
/// <value>Свойство <c>X</c> представляет координату x точки.</value>
public int X
{
get { return x; }
set { x = value; }
}
/// <value>Свойство <c>Y</c> представляет координату y точки.</value>
public int Y
{
get { return y; }
set { y = value; }
}
/// <summary>Этот конструктор инициализирует новый Point значением
/// (0,0).</summary>
public Point(): this(0,0) {}
/// <summary>Этот конструктор инициализирует новый Point параметрами
/// (<paramref name="xor"/>,<paramref name="yor"/>).</summary>
/// <param><c>xor</c> — это координата x нового Point.</param>
/// <param><c>xor</c> — это координата y нового Point.</param>
public Point(int xor, int yor) {
X = xor;
Y = yor;
}
/// <summary>Этот метод устанавливает для точки
/// заданные координаты.</summary>
/// <param><c>xor</c> это новая координата x.</param>
/// <param><c>yor</c> это новая координата y.</param>
/// <see cref="Translate"/>
public void Move(int xor, int yor) {
X = xor;
Y = yor;
}
/// <summary>Этот метод перемещает точку
/// на заданное смещение x и y.
/// <example>Например:
/// <code>
/// Point p = new Point(3,5);
/// p.Translate(-1,3);
/// </code>
/// дает в результате <c>p</c> со значением (2,8).
/// </example>
/// </summary>
/// <param><c>xor</c> это относительное смещение x.</param>
/// <param><c>yor</c> это относительное смещение y.</param>
/// <see cref="Move"/>
public void Translate(int xor, int yor) {
X += xor;
Y += yor;
}
/// <summary>Этот метод определяет, находятся ли два объекта Point в одном
/// месте.</summary>
/// <param><c>o</c> — это объект, который требуется сравнить с текущим объектом.
/// </param>
/// <returns>True, если у объектов Point одинаковое расположение и
/// одинаковый тип; иначе 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>Сообщить положение точки в виде строки.</summary>
/// <returns>Строка, представляющая положение точки в виде (x,y),
/// без пустого пространства в начале, конце или внутри.</returns>
public override string ToString() {
return "(" + X + "," + Y + ")";
}
/// <summary>Этот оператор определяет, находятся ли два объекта Point в одном
/// месте.</summary>
/// <param><c>p1</c> — это первый сравниваемый объект Point.</param>
/// <param><c>p2</c> это второй сравниваемый объект Point.</param>
/// <returns>True, если у объектов Point одинаковое расположение и
/// одинаковый тип; иначе 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;
}