<?xml version="1.0"?>
<clause number="24.2" title="Attribute specification">
  <paragraph>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 <non_terminal where="16.5">type-declaration</non_terminal>s (<hyperlink>16.5</hyperlink>),  <non_terminal where="17.2">class-member-declaration</non_terminal>s (<hyperlink>17.2</hyperlink>), <non_terminal where="20.2">interface-member-declaration</non_terminal>s (<hyperlink>20.2</hyperlink>), <non_terminal where="21.3">enum-member-declaration</non_terminal>s (<hyperlink>21.1</hyperlink>), <non_terminal where="17.6.2">accessor-declarations</non_terminal> (<hyperlink>17.6.2</hyperlink>), <non_terminal where="17.7">event-accessor-declarations</non_terminal> (<hyperlink>17.7</hyperlink>), and <non_terminal where="17.5.1">formal-parameter-list</non_terminal>s (<hyperlink>17.5.1</hyperlink>). </paragraph>
  <paragraph>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. <grammar_production><name><non_terminal where="24.2">global-attributes</non_terminal></name> : <rhs><non_terminal where="24.2">global-attribute-sections</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">global-attribute-section</non_terminal>s</name> : <rhs><non_terminal where="24.2">global-attribute-section</non_terminal></rhs><rhs><non_terminal where="24.2">global-attribute-sections</non_terminal><non_terminal where="24.2">global-attribute-section</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">global-attribute-section</non_terminal></name> : <rhs><terminal>[</terminal><non_terminal where="24.2">global-attribute-target-specifier</non_terminal><non_terminal where="24.2">attribute-list</non_terminal><terminal>]</terminal></rhs><rhs><terminal>[</terminal><non_terminal where="24.2">global-attribute-target-specifier</non_terminal><non_terminal where="24.2">attribute-list</non_terminal><terminal>,]</terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">global-attribute-target-specifier</non_terminal></name> : <rhs><non_terminal where="24.2">global-attribute-target</non_terminal><terminal>:</terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">global-attribute-target</non_terminal></name> : <rhs><terminal>assembly  </terminal></rhs></grammar_production><grammar_production><name>attributes</name> : <rhs><non_terminal where="24.2">attribute-sections</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">attribute-section</non_terminal>s</name> : <rhs><non_terminal where="24.2">attribute-section</non_terminal></rhs><rhs><non_terminal where="24.2">attribute-sections</non_terminal><non_terminal where="24.2">attribute-section</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">attribute-section</non_terminal></name> : <rhs><terminal>[</terminal><non_terminal where="24.2">attribute-target-specifier</non_terminal><opt/><non_terminal where="24.2">attribute-list</non_terminal><terminal>]</terminal></rhs><rhs><terminal>[</terminal><non_terminal where="24.2">attribute-target-specifier</non_terminal><opt/><non_terminal where="24.2">attribute-list</non_terminal><terminal>,]</terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">attribute-target-specifier</non_terminal></name> : <rhs><non_terminal where="24.2">attribute-target</non_terminal><terminal>:</terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">attribute-target</non_terminal></name> : <rhs><terminal>field </terminal></rhs><rhs><terminal>event </terminal></rhs><rhs><terminal>method </terminal></rhs><rhs><terminal>param </terminal></rhs><rhs><terminal>property </terminal></rhs><rhs><terminal>return  </terminal></rhs><rhs><terminal>type  </terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">attribute-list</non_terminal></name> : <rhs><non_terminal where="24.2">attribute</non_terminal></rhs><rhs><non_terminal where="24.2">attribute-list</non_terminal><terminal>,</terminal><non_terminal where="24.2">attribute</non_terminal></rhs></grammar_production><grammar_production><name>attribute</name> : <rhs><non_terminal where="24.2">attribute-name</non_terminal><non_terminal where="24.2">attribute-arguments</non_terminal><opt/></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">attribute-name</non_terminal></name> : <rhs><non_terminal where="10.8">type-name</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">attribute-arguments</non_terminal></name> : <rhs><terminal>(</terminal><non_terminal where="24.2">positional-argument-list</non_terminal><opt/><terminal>)</terminal></rhs><rhs><terminal>(</terminal><non_terminal where="24.2">positional-argument-list</non_terminal><terminal>,</terminal><non_terminal where="24.2">named-argument-list</non_terminal><terminal>)</terminal></rhs><rhs><terminal>(</terminal><non_terminal where="24.2">named-argument-list</non_terminal><terminal>)</terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">positional-argument-list</non_terminal></name> : <rhs><non_terminal where="24.2">positional-argument</non_terminal></rhs><rhs><non_terminal where="24.2">positional-argument-list</non_terminal><terminal>,</terminal><non_terminal where="24.2">positional-argument</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">positional-argument</non_terminal></name> : <rhs><non_terminal where="24.2">attribute-argument-expression</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">named-argument-list</non_terminal></name> : <rhs><non_terminal where="24.2">named-argument</non_terminal></rhs><rhs><non_terminal where="24.2">named-argument-list</non_terminal><terminal>,</terminal><non_terminal where="24.2">named-argument</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">named-argument</non_terminal></name> : <rhs><non_terminal where="9.4.2">identifier</non_terminal><terminal>=</terminal><non_terminal where="24.2">attribute-argument-expression</non_terminal></rhs></grammar_production><grammar_production><name><non_terminal where="24.2">attribute-argument-expression</non_terminal></name> : <rhs><non_terminal where="14.14">expression</non_terminal></rhs></grammar_production></paragraph>
  <paragraph>An attribute consists of an <non_terminal where="24.2">attribute-name</non_terminal> 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 <non_terminal where="24.2">attribute-argument-expression</non_terminal>, which, together, are constrained by the same rules as simple assignment.) The order of named arguments is not significant. </paragraph>
  <paragraph>The <non_terminal where="24.2">attribute-name</non_terminal> identifies an attribute class. If the form of <non_terminal where="24.2">attribute-name</non_terminal> is <non_terminal where="10.8">type-name</non_terminal> then this name must refer to an attribute class. Otherwise, a compile-time error occurs. <example>[Example: The example <code_example><![CDATA[
class Class1 {}  
[Class1] class Class2 {}  // Error  
]]></code_example>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]</example> </paragraph>
  <paragraph>Certain contexts permit the specification of an attribute on more than one target. A program can explicitly specify the target by including an <non_terminal where="24.2">attribute-target-specifier</non_terminal>. When an attribute is placed at the global level, a <non_terminal where="24.2">global-attribute-target-specifier</non_terminal> is required. In all other locations, a reasonable default is applied, but an <non_terminal where="24.2">attribute-target-specifier</non_terminal> 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, <non_terminal where="24.2">attribute-target-specifier</non_terminal>s can be omitted except at the global level. The potentially ambiguous contexts are resolved as follows: <list><list_item> 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 <non_terminal where="24.2">attribute-target-specifier</non_terminal>, the attribute applies to the delegate. The presence of the type <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the delegate; the presence of the return <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the return value. </list_item><list_item> 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 <non_terminal where="24.2">attribute-target-specifier</non_terminal>, the attribute applies to the method. The presence of the method <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the method; the presence of the return <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the return value. </list_item><list_item> An attribute specified on an operator declaration can apply either to the operator being declared or to its return value of this declaration. In the absence of an <non_terminal where="24.2">attribute-target-specifier</non_terminal>, the attribute applies to the operator. The presence of the type <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the operator; the presence of the return <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the return value. </list_item><list_item> An attribute specified on an event declaration that omits event accessors 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 <non_terminal where="24.2">attribute-target-specifier</non_terminal>, the attribute applies to the event declaration. The presence of the event <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the event; the presence of the field <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the field; and the presence of the method <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the methods. </list_item><list_item> 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 <non_terminal where="24.2">attribute-target-specifier</non_terminal>, the attribute applies to the method. The presence of the method <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the method; the presence of the return <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the return value. </list_item><list_item> 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 <non_terminal where="24.2">attribute-target-specifier</non_terminal>, the attribute applies to the method. The presence of the method <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the method; the presence of the param <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the parameter. </list_item><list_item> 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 <non_terminal where="24.2">attribute-target-specifier</non_terminal>, the attribute applies to the method. The presence of the method <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the method; the presence of the param <non_terminal where="24.2">attribute-target-specifier</non_terminal> indicates that the attribute applies to the parameter. </list_item></list></paragraph>
  <paragraph>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. </paragraph>
  <paragraph>By convention, attribute classes are named with a suffix of Attribute. An <non_terminal where="24.2">attribute-name</non_terminal> of the form  <non_terminal where="10.8">type-name</non_terminal> 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 <non_terminal where="24.2">attribute-name</non_terminal> is spelled using a verbatim identifier (<hyperlink>9.4.2</hyperlink>), then only an attribute without a suffix is matched, thus enabling such an ambiguity to be resolved. <example>[Example: The example <code_example><![CDATA[
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 {}  
]]></code_example>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: <code_example><![CDATA[
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 {}  
]]></code_example>end example]</example> </paragraph>
  <paragraph>It is a compile-time error to use a single-use attribute class more than once on the same entity. <example>[Example: The example <code_example><![CDATA[
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 {}  
]]></code_example>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]</example> </paragraph>
  <paragraph>An expression E is an <non_terminal where="24.2">attribute-argument-expression</non_terminal> if all of the following statements are true: <list><list_item> The type of E is an attribute parameter type (<hyperlink>24.1.3</hyperlink>). </list_item><list_item> At compile-time, the value of E can be resolved to one of the following: </list_item><list><list_item> A constant value. </list_item><list_item> A System.Type object. </list_item><list_item> A one-dimensional array of <non_terminal where="24.2">attribute-argument-expression</non_terminal>s. </list_item></list></list></paragraph>
  <paragraph>
    <example>[Example: For example: <code_example><![CDATA[
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 {}  
]]></code_example>end example]</example>
  </paragraph>
</clause>
