ECMA-334 C# Language Specification

24.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-declarations (16.5), class-member-declarations (17.2), interface-member-declarations (20.2), enum-member-declarations (21.1), accessor-declarations (17.6.2), event-accessor-declarations (17.7), and formal-parameter-lists (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-attributes
global-attribute-sections
global-attribute-section
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
assembly
attribute-sections
attribute-section
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
field
event
method
param
property
return
type
attribute-list
attribute
attribute-list , 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
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. [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]

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-specifiers can be omitted except at the global level. The potentially ambiguous contexts are resolved as follows:

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. [Example: 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 [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 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:

[Example: For 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 {}  
end example]