Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp Language Specification.doc
Скачиваний:
12
Добавлен:
26.09.2019
Размер:
4.75 Mб
Скачать

17.1.3Типы параметров атрибута

Типы позиционных и именованных параметров для класса атрибута ограничены типами параметров атрибута, к которым относятся:

  • один из следующих типов: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong и ushort;

  • тип object;

  • тип System.Type;

  • перечисляемый тип, если и он имеет общую доступность, и типы, в которые он вложен (если вложен), также имеют общую доступность (§17.2);

  • одномерные массивы указанных выше типов.

Аргумент конструктора или общее поле, которые не имеют один из этих типов, не могут использоваться в качестве позиционных или именованных параметров в спецификации атрибута.

17.2Спецификация атрибута

Спецификация атрибута — это применение предварительно определенного атрибута к объявлению. Атрибут является частью дополнительных декларативных сведений, задаваемых для объявления. Атрибуты могут задаваться в глобальной области видимости (чтобы задать атрибуты для содержащей сборки или модуля) и для объявлений_типов (§9.6), объявлений_членов_класса (§10.1.5), объявлений_членов_интерфейса (§13.2), объявлений_членов_структуры (§11.2), объявлений_членов_перечисления (§14.3), объявлений_методов_доступа (§10.7.2), объявлений_метода_доступа_к_событиям (§10.8.1) и списков_формальных_параметров (§10.6.1).

Атрибуты задаются в разделах атрибутов. Раздел атрибутов состоит из пары квадратных скобок, которые окружают список из одного или более атрибутов, разделенных запятыми. Порядок указания атрибутов в таком списке и порядок размещения разделов, вложенных в одну и ту же программную сущность, не имеет значения. Например, спецификации атрибутов [A][B], [B][A], [A, B] и [B, A] эквивалентны.

глобальные_атрибуты: разделы_глобальных_атрибутов

разделы_глобальных_атрибутов: раздел_глобальных_атрибутов разделы_глобальных_атрибутов раздел_глобальных_атрибутов

раздел_глобальных_атрибутов: [ целевая_спецификация_глобального_атрибута список_атрибутов ] [ целевая_спецификация_глобального_атрибута список_атрибутов , ]

целевая_спецификация_глобального_атрибута: цель_глобального_атрибута :

цель_глобального_атрибута: assembly module

атрибуты: разделы_атрибутов

разделы_атрибутов: раздел_атрибутов разделы_атрибутов раздел_атрибутов

раздел_атрибутов: [ целевая_спецификация_атрибутанеобязательно список_атрибутов ] [ целевая_спецификация_атрибутанеобязательно список_атрибутов , ]

целевая_спецификация_атрибута: цель_атрибута :

цель_атрибута: field event method param property return type

список_атрибутов: атрибут список_атрибутов , атрибут

атрибут: имя_атрибута аргументы_атрибутанеобязательно

имя_атрибута: имя_типа

аргументы_атрибута: ( список_аргументов_по_положениюнеобязательно ) ( список_аргументов_по_положению , список_именованных_аргументов ) ( список_именованных_аргументов )

список_аргументов_по_положению: аргумент_по_положению список_аргументов_по_положению , аргумент_по_положению

аргумент_по_положению: имя_аргументанеобязательно выражение_аргумента_атрибута

список_именованных_аргументов: именованный_аргумент список_именованных_аргументов , именованный_аргумент

именованный_аргумент: идентификатор = выражение_аргумента_атрибута

выражение_аргумента_атрибута: выражение

Атрибут состоит из имени_атрибута и необязательного списка позиционных и именованных аргументов. Позиционные аргументы (если они имеются) предшествуют именованным аргументам. Позиционный аргумент состоит из выражения_аргумента_атрибута; именованный аргумент состоит из имени, за которым следует знак равенства, далее следует выражение_аргумента_атрибута, которые все вместе ограничены теми же правилами, которые применяются для простого присваивания. Порядок именованных аргументов не имеет значения.

Имя_атрибута идентифицирует класс атрибута. Если имя_атрибута имеет вид имени_типа, это имя должно ссылаться на класс атрибута. В противном случае произойдет ошибка времени компиляции. Например:

class Class1 {}

[Class1] class Class2 {} // Error

В результате возникает ошибка времени компиляции, так как предпринята попытка использовать Class1 в качестве класса атрибута, хотя Class1 не является классом атрибута.

Определенные контексты разрешают спецификацию атрибута более чем для одного целевого объекта. Программа может явно задать целевой объект включением описателя_целевого_объекта_атрибута. Если атрибут размещен на глобальном уровне, требуется описатель_целевого_объекта_глобального_атрибута. Во всех остальных расположениях применяется обоснованное значение по умолчанию, но описатель_целевого_объекта_атрибута может использоваться для подтверждения или переопределения значения по умолчанию в определенных неоднозначных ситуациях (или просто для подтверждения значения по умолчанию в не вызывающих сомнения случаях). Таким образом, описатели_целевого_объекта_атрибута обычно могут быть опущены, кроме случаев их использования на глобальном уровне. В случае потенциально неоднозначных контекстов решение принимается следующим образом:

  • атрибут, заданный в глобальной области видимости, может применяться либо к конечной сборке, либо к конечному модулю. Для этого контекста нет значения по умолчанию, поэтому в этом контексте всегда требуется описатель_целевого_объекта_атрибута. Наличие описателя_целевого_объекта_атрибута assembly указывает, что атрибут применяется к конечной сборке; наличие описателя_целевого_объекта_атрибута module указывает, что атрибут применяется к конечному модулю;

  • атрибут, заданный в объявлении делегата, может применяться либо к объявляемому делегату, либо к его возвращаемому значению. При отсутствии описателя_целевого_объекта_атрибута атрибут применяется к делегату. Наличие описателя_целевого_объекта_атрибута type указывает, что атрибут применяется к делегату; наличие описателя_целевого_объекта_атрибута return указывает, что атрибут применяется к возвращаемому значению;

  • атрибут, заданный в объявлении метода, может применяться либо к объявляемому методу, либо к его возвращаемому значению. При отсутствии описателя_целевого_объекта_атрибута атрибут применяется к методу. Наличие описателя_целевого_объекта_атрибута method указывает, что атрибут применяется к методу; наличие описателя_целевого_объекта_атрибута return указывает, что атрибут применяется к возвращаемому значению;

  • атрибут, заданный в объявлении оператора, может применяться либо к объявляемому оператору, либо к его возвращаемому значению. При отсутствии описателя_целевого_объекта_атрибута атрибут применяется к оператору. Наличие описателя_целевого_объекта_атрибута method указывает, что атрибут применяется к методу; наличие описателя_целевого_объекта_атрибута return указывает, что атрибут применяется к возвращаемому значению;

  • атрибут, заданный в объявлении события, в котором опущены методы доступа к событиям, может применяться к объявляемому событию, к связанному полю (если событие не является абстрактным) или к связанным методам add и remove. При отсутствии описателя_целевого_объекта_атрибута атрибут применяется к событию. Наличие описателя_целевого_объекта_атрибута event указывает, что атрибут применяется к событию; наличие описателя_целевого_объекта_атрибута field указывает, что атрибут применяется к полю; а наличие описателя_целевого_объекта_атрибута method указывает, что атрибут применяется к методам;

  • атрибут, заданный в объявлении метода доступа get для объявления свойства или индексатора, может применяться либо к связанному методу, либо к его возвращаемому значению. При отсутствии описателя_целевого_объекта_атрибута атрибут применяется к методу. Наличие описателя_целевого_объекта_атрибута method указывает, что атрибут применяется к методу; наличие описателя_целевого_объекта_атрибута return указывает, что атрибут применяется к возвращаемому значению;

  • атрибут, указанный в объявлении метода доступа set для объявления свойства или индексатора, может применяться либо к связанному методу, либо к его одиночному неявному параметру. При отсутствии описателя_целевого_объекта_атрибута атрибут применяется к методу. Наличие описателя_целевого_объекта_атрибута method указывает, что атрибут применяется к методу; наличие описателя_целевого_объекта_атрибута param указывает, что атрибут применяется к параметру; наличие описателя_целевого_объекта_атрибута return указывает, что атрибут применяется к возвращаемому значению;

  • атрибут, заданный в объявлении метода доступа add или remove для объявления события, может применяться или к связанному методу, или к его одиночному параметру. При отсутствии описателя_целевого_объекта_атрибута атрибут применяется к методу. Наличие описателя_целевого_объекта_атрибута method указывает, что атрибут применяется к методу; наличие описателя_целевого_объекта_атрибута param указывает, что атрибут применяется к параметру; наличие описателя_целевого_объекта_атрибута return указывает, что атрибут применяется к возвращаемому значению.

В других контекстах включение описателя_целевого_объекта_атрибута разрешено, но излишне. Например, объявление класса может или включать, или опускать описатель type:

[type: Author("Brian Kernighan")] class Class1 {}

[Author("Dennis Ritchie")] class Class2 {}

Является ошибкой задание недопустимого описателя_целевого_объекта_атрибута. Например, описатель param нельзя использовать в объявлении класса:

[param: Author("Brian Kernighan")] // Error class Class1 {}

Классы атрибутов принято именовать с помощью суффикса Attribute. Имя_атрибута вида имя_типа может или включать, или опускать этот суффикс. Если обнаружен класс атрибута и с этим суффиксом, и без суффикса, эта неоднозначность приводит к ошибке времени компиляции. Если имя_атрибута записывается таким образом, что его самый правый идентификатор является буквальным идентификатором (§2.4.2), то сопоставляется только атрибут без суффикса, позволяя таким образом разрешить неоднозначность. Например:

using System;

[AttributeUsage(AttributeTargets.All)] public class X: Attribute {}

[AttributeUsage(AttributeTargets.All)] public class XAttribute: Attribute {}

[X] // Error: ambiguity class Class1 {}

[XAttribute] // Refers to XAttribute class Class2 {}

[@X] // Refers to X class Class3 {}

[@XAttribute] // Refers to XAttribute class Class4 {}

Здесь показаны два класса атрибутов с именами X и XAttribute. Атрибут [X] является неоднозначным, так как он может ссылаться или на X, или на XAttribute. Использование буквального идентификатора позволяет указать точное намерение в таких редких случаях. Атрибут [XAttribute] не является неоднозначным (хотя он мог бы им быть, если бы имелся класс атрибута с именем XAttributeAttribute). Если удаляется объявление для класса X, то оба атрибута ссылаются на класс атрибута с именем XAttribute, как это показано в следующем примере:

using System;

[AttributeUsage(AttributeTargets.All)] public class XAttribute: Attribute {}

[X] // Refers to XAttribute class Class1 {}

[XAttribute] // Refers to XAttribute class Class2 {}

[@X] // Error: no attribute named "X" class Class3 {}

Использование класса атрибута одноразового использования более одного раза для одной и той же сущности является ошибкой времени компиляции. Например:

using System;

[AttributeUsage(AttributeTargets.Class)] public class HelpStringAttribute: Attribute { string value;

public HelpStringAttribute(string value) { this.value = value; }

public string Value { get {...} } }

[HelpString("Description of Class1")] [HelpString("Another description of Class1")] public class Class1 {}

В результате возникает ошибка времени компиляции, так как предпринимается попытка использования HelpString, который является классом атрибута одноразового использования, более одного раза в объявлении Class1.

Выражение E является выражением_аргумента_атрибута, если верны все следующие утверждения:

  • тип E — это тип параметра атрибута (§17.1.3);

  • во время компиляции значение E может быть разрешено в одно из следующего:

  • постоянное значение;

  • объект System.Type;

  • одномерный массив выражений_аргумента_атрибута.

Пример:

using System;

[AttributeUsage(AttributeTargets.Class)] public class TestAttribute: Attribute { public int P1 { get {...} set {...} }

public Type P2 { get {...} set {...} }

public object P3 { get {...} set {...} } }

[Test(P1 = 1234, P3 = new int[] {1, 3, 5}, P2 = typeof(float))] class MyClass {}

Выражение_typeof (§7.6.11), используемое в качестве выражения аргумента атрибута, может ссылаться на неуниверсальный тип, закрытый сконструированный тип или на несвязанный универсальный тип, но не может ссылаться на открытый тип. Это обеспечивает возможность разрешения выражения во время компиляции.

class A: Attribute { public A(Type t) {...} }

class G<T> { [A(typeof(T))] T t; // Error, open type in attribute }

class X { [A(typeof(List<int>))] int x; // Ok, closed constructed type [A(typeof(List<>))] int y; // Ok, unbound generic type }

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]