ECMA-334 C# Language Specification24.2: Attribute specification |
Attribute specification is the application of a previously defined attribute to a declaration. An attribute is a piece of additional declarative information that is specified for a declaration. Attributes can be specified at global scope (to specify attributes on the containing assembly) and for type-declaration
s (16.5), class-member-declaration
s (17.2), interface-member-declaration
s (20.2), enum-member-declaration
s (21.1), accessor-declarations
(17.6.2), event-accessor-declarations
(17.7), and formal-parameter-list
s (17.5.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-attribute-sections
global-attribute-section
global-attribute-sections
global-attribute-section
[
global-attribute-target-specifier
attribute-list
]
[
global-attribute-target-specifier
attribute-list
,]
global-attribute-target
:
assembly
attribute-sections
attribute-section
attribute-sections
attribute-section
[
attribute-target-specifier
opt attribute-list
]
[
attribute-target-specifier
opt attribute-list
,]
attribute-target
:
field
event
method
param
property
return
type
attribute
attribute-list
,
attribute
attribute-name
attribute-arguments
opt type-name
(
positional-argument-list
opt )
(
positional-argument-list
,
named-argument-list
)
(
named-argument-list
)
positional-argument
positional-argument-list
,
positional-argument
attribute-argument-expression
named-argument
named-argument-list
,
named-argument
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.
The attribute-name
identifies an attribute class. If the form of attribute-name
is type-name
then this name must refer to an attribute class. Otherwise, a compile-time error occurs.
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]
class Class1 {}
[Class1] class Class2 {} // Error
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
. When an attribute is placed at the global level, a global-attribute-target-specifier
is required. In all other locations, a reasonable default is applied, but an attribute-target-specifier
can be used to affirm or override the default in certain ambiguous cases (or to just affirm the default in non-ambiguous cases). Thus, typically, attribute-target-specifier
s can be omitted except at the global level. The potentially ambiguous contexts are resolved as follows:
attribute-target-specifier
, the attribute applies to the delegate. The presence of the type attribute-target-specifier
indicates that the attribute applies to the delegate; the presence of the return attribute-target-specifier
indicates that the attribute applies to the return value. attribute-target-specifier
, the attribute applies to the method. The presence of the method attribute-target-specifier
indicates that the attribute applies to the method; the presence of the return attribute-target-specifier
indicates that the attribute applies to the return value. attribute-target-specifier
, the attribute applies to the operator. The presence of the type attribute-target-specifier
indicates that the attribute applies to the operator; the presence of the return attribute-target-specifier
indicates that the attribute applies to the return value. attribute-target-specifier
, the attribute applies to the event declaration. The presence of the event attribute-target-specifier
indicates that the attribute applies to the event; the presence of the field attribute-target-specifier
indicates that the attribute applies to the field; and the presence of the method attribute-target-specifier
indicates that the attribute applies to the methods. attribute-target-specifier
, the attribute applies to the method. The presence of the method attribute-target-specifier
indicates that the attribute applies to the method; the presence of the return attribute-target-specifier
indicates that the attribute applies to the return value. attribute-target-specifier
, the attribute applies to the method. The presence of the method attribute-target-specifier
indicates that the attribute applies to the method; the presence of the param attribute-target-specifier
indicates that the attribute applies to the parameter. attribute-target-specifier
, the attribute applies to the method. The presence of the method attribute-target-specifier
indicates that the attribute applies to the method; the presence of the param attribute-target-specifier
indicates that the attribute applies to the parameter. An implementation may accept other attribute target specifiers, the purpose of which is implementation-defined. 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
of the form type-name
may either include or omit this suffix. If an attribute class is found both with and without this suffix, an ambiguity is present, and a compile-time error shall be issued. If the attribute-name
is spelled using a verbatim identifier (9.4.2), then only an attribute without a suffix is matched, thus enabling such an ambiguity to be resolved.
shows two attribute classes named X and XAttribute. The attribute [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 [XAttribute] is not ambiguous (although it would be if there was 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 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 {}
end example]
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 {}
It is a compile-time error to use a single-use attribute class more than once on the same entity.
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]
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 {}
An expression E is an attribute-argument-expression
if all of the following statements are true:
attribute-argument-expression
s.
end 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 {}