ECMA-334: 24.2 Attribute specification


Jump to: navigation, search
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:
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:
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
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 type indicates that the attribute applies to the delegate; an attribute-target equal to return indicates 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 method indicates that the attribute applies to the method; an attribute-target equal to return indicates 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 method indicates that the attribute applies to the operator; an attribute-target equal to return indicates 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 method indicates that the attribute applies to the method; an attribute-target equal to return indicates that the attribute applies to the return value.
  • 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 method indicates that the attribute applies to the method; an attribute-target equal to param indicates that the attribute applies to the parameter.
  • 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 event indicates that the attribute applies to the event; an attribute-target equal to field indicates that the attribute applies to the field; and an attribute-target equal to method indicates that the attribute applies to the methods.
  • 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 method indicates that the attribute applies to the method; an attribute-target equal to param indicates that the attribute applies to the parameter.

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.
  • 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.Attribute then the type is the result of this step.
    • The characters Attribute are 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 from System.Attribute then the type is the result of this step.
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 E is an attribute parameter type (§24.1.3).
  • At compile-time, the value of E can 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.

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



Personal tools