ECMA-334: 24.2 Attribute specification
| C# Language Specification |
|
| © 2006 ECMA International |
24.2 Attribute specification
Attribute specification is the application of a previously defined attribute to a program entity. An attribute is a piece of additional declarative information that is specified for a program entity. Attributes can be specified at global scope (to specify attributes on the containing assembly) and for type-declarations (§16.6), class-member-declarations (§17.1.4), struct-member-declarations (§18.2), interface-member-declarations (§20.2), enum-member-declarations (§21.1), accessor-declarations (§17.6.2), event-accessor-declarations (§17.7), elements of formal-parameter-lists (§17.5.1), and elements of type-parameter-lists (§25.1.1).
Attributes are specified in attribute sections. An attribute section consists of a pair of square brackets, which
surround a comma-separated list of one or more attributes. The order in which attributes are specified in
such a list, and the order in which sections attached to the same program entity are arranged, is not
significant. For instance, the attribute specifications [A][B], [B][A], [A, B], and [B, A] are equivalent.
- global-attributes:
- global-attribute-sections
- global-attribute-sections:
- global-attribute-section
- global-attribute-sections global-attribute-section
- global-attribute-section:
[global-attribute-target-specifier attribute-list][global-attribute-target-specifier attribute-list, ]
- global-attribute-target-specifier:
- global-attribute-target
:
- global-attribute-target
- global-attribute-target:
- identifier
- keyword
- attributes:
- attribute-sections
- attribute-sections:
- attribute-section
- attribute-sections attribute-section
- attribute-section:
[attribute-target-specifieropt attribute-list][attribute-target-specifieropt attribute-list, ]
- attribute-target-specifier:
- attribute-target
:
- attribute-target
- attribute-target:
- identifier
- keyword
- attribute-list:
- attribute
- attribute-list
,attribute
- attribute:
- attribute-name attribute-argumentsopt
- attribute-name:
- type-name
- attribute-arguments:
(positional-argument-listopt)(positional-argument-list,named-argument-list)(named-argument-list)
- positional-argument-list:
- positional-argument
- positional-argument-list
,positional-argument
- positional-argument:
- attribute-argument-expression
- named-argument-list:
- named-argument
- named-argument-list
,named-argument
- named-argument:
- identifier
=attribute-argument-expression
- identifier
- attribute-argument-expression:
- expression
An attribute consists of an attribute-name and an optional list of positional and named arguments. The positional arguments (if any) precede the named arguments. A positional argument consists of an attribute-argument-expression; a named argument consists of a name, followed by an equal sign, followed by an attribute-argument-expression, which, together, are constrained by the same rules as simple assignment. The order of named arguments is not significant.
[Note: For convenience, a trailing comma is allowed in a global-attribute-section and an attribute-section, just as one is allowed in an array-initializer (§19.6). end note]
The attribute-name identifies an attribute class. type-name shall refer to an attribute class. Otherwise, a compile-time error occurs. [Example: The example
class Class1 {} [Class1] class Class2 {} // Error
results in a compile-time error because it attempts to use Class1 as an attribute class when Class1 is not
an attribute class. end example]
When an attribute is placed at the global level, a global-attribute-target-specifier is required. The only
standardized global-attribute-target name is assembly. This target name shall only be used in the context
of an assembly.
The only standardized attribute-target names are event, field, method, param, property, return,
type, and typevar. These target names shall only be used in the following contexts:
-
event— an event.
-
-
field— a field. A field-like event (i.e., one without accessors) can also have an attribute with this target.
-
-
method— a constructor, finalizer, method, operator, property get and set accessors, indexer get and set accessors, and event add and remove accessors. A field-like event (i.e., one without accessors) can also have an attribute with this target.
-
-
param— a property set accessor, an indexer set accessor, event add and remove accessors, and a parameter in a constructor, method, and operator.
-
-
property— a property and an indexer.
-
-
return— a delegate, method, operator, property get accessor, and indexer get accessor.
-
-
type— a delegate, class, struct, enum, and interface.
-
-
typevar— a type parameter.
-
Certain contexts permit the specification of an attribute on more than one target. A program can explicitly specify the target by including an attribute-target-specifier. In the absence of an attribute-target-specifier, a reasonable default is applied, but an attribute-target-specifier can be used to affirm or override the default in certain ambiguous cases (or just to affirm the default in non-ambiguous cases). Thus, typically, attribute-target-specifiers can be omitted. The potentially ambiguous contexts are resolved as follows (using equality as defined in §9.4.2):
- An attribute specified on a delegate declaration can apply either to the delegate being declared or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the delegate. An attribute-target equal to
typeindicates that the attribute applies to the delegate; an attribute-target equal toreturnindicates that the attribute applies to the return value.
- An attribute specified on a delegate declaration can apply either to the delegate being declared or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the delegate. An attribute-target equal to
- An attribute specified on a method declaration can apply either to the method being declared or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the method. An attribute-target equal to
methodindicates that the attribute applies to the method; an attribute-target equal toreturnindicates that the attribute applies to the return value.
- An attribute specified on a method declaration can apply either to the method being declared or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the method. An attribute-target equal to
- An attribute specified on an operator declaration can apply either to the operator being declared or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the operator. An attribute-target equal to
methodindicates that the attribute applies to the operator; an attribute-target equal toreturnindicates that the attribute applies to the return value.
- An attribute specified on an operator declaration can apply either to the operator being declared or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the operator. An attribute-target equal to
- An attribute specified on a get accessor declaration for a property or indexer declaration can apply either to the associated method or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the method. An attribute-target equal to
methodindicates that the attribute applies to the method; an attribute-target equal toreturnindicates that the attribute applies to the return value.
- An attribute specified on a get accessor declaration for a property or indexer declaration can apply either to the associated method or to its return value. In the absence of an attribute-target-specifier, the attribute applies to the method. An attribute-target equal to
- An attribute specified on a set accessor for a property or indexer declaration can apply either to the associated method or to its lone implicit parameter. In the absence of an attribute-target-specifier, the attribute applies to the method. An attribute-target equal to
methodindicates that the attribute applies to the method; an attribute-target equal toparamindicates that the attribute applies to the parameter.
- An attribute specified on a set accessor for a property or indexer declaration can apply either to the associated method or to its lone implicit parameter. In the absence of an attribute-target-specifier, the attribute applies to the method. An attribute-target equal to
- An attribute specified on an event declaration that omits event-accessor-declarations can apply to the event being declared, to the associated field (if the event is not abstract), or to the associated add and remove methods. In the absence of an attribute-target-specifier, the attribute applies to the event declaration. An attribute-target equal to
eventindicates that the attribute applies to the event; an attribute-target equal tofieldindicates that the attribute applies to the field; and an attribute-target equal tomethodindicates that the attribute applies to the methods.
- An attribute specified on an event declaration that omits event-accessor-declarations can apply to the event being declared, to the associated field (if the event is not abstract), or to the associated add and remove methods. In the absence of an attribute-target-specifier, the attribute applies to the event declaration. An attribute-target equal to
- In the case of an event declaration that does not omit event-accessor-declarations, an attribute specified on an add or remove accessor declaration for an event declaration can apply either to the associated method or to its lone parameter. In the absence of an attribute-target-specifier, the attribute applies to the method. An attribute-target equal to
methodindicates that the attribute applies to the method; an attribute-target equal toparamindicates that the attribute applies to the parameter.
- In the case of an event declaration that does not omit event-accessor-declarations, an attribute specified on an add or remove accessor declaration for an event declaration can apply either to the associated method or to its lone parameter. In the absence of an attribute-target-specifier, the attribute applies to the method. An attribute-target equal to
An implementation can accept other attribute target specifiers, the purposes of which are implementationdefined. However, an implementation that does not recognize such a target, shall issue a warning.
By convention, attribute classes are named with a suffix of Attribute. An attribute-name can either
include or omit this suffix. Specifically, an attribute-name is resolved as follows:
- If the right-most identifier of the attribute-name is a verbatim identifier (§9.4.2), then the attribute-name is resolved as a type-name (§10.8). If the result is not a type derived from
System.Attribute, a compile-time error occurs.
- If the right-most identifier of the attribute-name is a verbatim identifier (§9.4.2), then the attribute-name is resolved as a type-name (§10.8). If the result is not a type derived from
- Otherwise,
- The attribute-name is resolved as a type-name (§10.8) except any errors are suppressed. If this resolution is successful and results in a type derived from
System.Attributethen the type is the result of this step. - The characters
Attributeare appended to the right-most identifier in the attribute-name and the resulting string of tokens is resolved as a type-name (§10.8) except any errors are suppressed. If this resolution is successful and results in a type derived fromSystem.Attributethen the type is the result of this step.
- The attribute-name is resolved as a type-name (§10.8) except any errors are suppressed. If this resolution is successful and results in a type derived from
- Otherwise,
- If exactly one of the two steps above results in a type derived from
System.Attribute, then that type is the result of the attribute-name. Otherwise a compile-time error occurs.
[Example: Informally, when attempting to resolve an attribute-name, if an attribute class is found both with
and without the Attribute suffix, an ambiguity is present, and a compile-time error is issued. If the
attribute-name is spelled such that its right-most identifier is a verbatim identifier (§9.4.2), then only an
attribute without a suffix is matched, thus enabling such an ambiguity to be resolved. The example
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 {}
shows two attribute classes named X and XAttribute. The attribute reference [X] is ambiguous, since it
could refer to either X or XAttribute. Using a verbatim identifier allows the exact intent to be specified in
such rare cases. The attribute reference [XAttribute] is not ambiguous (although it would be if there were an attribute class named XAttributeAttribute!). If the declaration for class X is removed, then both
attributes refer to the attribute class named XAttribute, as follows:
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 {}
end example]
It is a compile-time error to use a single-use attribute class more than once on the same entity. [Example: The example
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 {}
results in a compile-time error because it attempts to use HelpString, which is a single-use attribute class,
more than once on the declaration of Class1. end example]
An expression E is an attribute-argument-expression if all of the following statements are true:
- The type of
Eis an attribute parameter type (§24.1.3). - At compile-time, the value of
Ecan be resolved to one of the following:- A constant value.
- A typeof-expression (§14.5.11) specifying a non-generic type, a closed constructed type (§25.5.2), or an unbound generic type (§25.5).
- A one-dimensional array of attribute-argument-expressions.
- The type of
[Example:
using System; [AttributeUsage(AttributeTargets.Class)] public class MyAttribute: Attribute { public int P1 { get {…} set {…} } public Type P2 { get {…} set {…} } public object P3 { get {…} set {…} } } [My(P1 = 1234, P3 = new int[]{1, 3, 5}, P2 = typeof(float))] class MyClass {} class C<T> { [My(P2 = typeof(T))] // Error – T not a closed type. int x1; [My(P2 = typeof(C<T>))] // Error – C<T> not a closed type. int x2; [My(P2 = typeof(C<int>))] // Ok int x3; [My(P2 = typeof(C<>))] // Ok int x4; }
end example]
The attributes of a type declared in multiple parts are determined by combining, in an unspecified order, the attributes of each of its parts. If the same attribute is placed on multiple parts, it is equivalent to specifying that attribute multiple times on the type. [Example: The two parts:
[Attr1, Attr2("hello")] partial class A {} [Attr3, Attr2("goodbye")] partial class A {}
are equivalent to the following single declaration:
[Attr1, Attr2("hello"), Attr3, Attr2("goodbye")] class A {}
end example]
Attributes on type parameters combine in the same way.