Attributes

[[target:]? attribute-name (
positional-param+ |
[named-param = expr]+ |
positional-param+, [named-param = expr]+)?]

Attributes are language constructs that can decorate a code element (assemblies, modules, types, members, return values, and parameters) with additional information.

In every language, you specify information associated with the types, methods, parameters, and other elements of your program. For example, a type can specify a list of interfaces it derives from, or a parameter can specify modifiers, such as the ref modifier in C#. The limitation of this approach is you can associate information with code elements using only the predefined constructs that the language provides.

Attributes allow programmers to extend the types of information associated with these code elements. For example, serialization in the .NET Framework uses various serialization attributes applied to types and fields to define how these code elements are serialized. This approach is more flexible than requiring the language to have special syntax for serialization.

Attribute Classes

An attribute is defined by a class that inherits (directly or indirectly) from the abstract class System.Attribute. When specifying an attribute to an element, the attribute name is the name of the type. By convention, the derived type name ends in Attribute, although specifying the suffix is not required when specifying the attribute.

In this example, the Foo class is specified as serializable using the Serializable attribute:

[Serializable]
public class Foo {...}

The Serializable attribute is actually a type declared in the System namespace, as follows:

class SerializableAttribute : Attribute {...}

We could also specify the Serializable attribute using its fully qualified type name, as follows:

[System.SerializableAttribute]
public class Foo {...}

The preceding two examples of using the Serializable attribute are semantically identical.

The C# language and the FCL include a number of predefined attributes. For more information about the other attributes included in the FCL and creating your own attributes, see Chapter 14.

Named and Positional Parameters

Attributes can take parameters, which can specify additional information on the code element beyond the mere presence of the attribute.

In this example, the class Foo is specified as obsolete using the Obsolete attribute. This attribute allows parameters to be included to specify both a message and whether the compiler should treat the use of this class as an error:

[Obsolete("Use Bar class instead", IsError=true)]
public class Foo {...}

Attribute parameters fall into one of two categories: positional and named. In the preceding example, Use Bar class instead is a positional parameter and IsError=true is a named parameter.

The positional parameters for an attribute correspond to the parameters passed to the attribute type’s public constructors. The named parameters for an attribute correspond to the set of public read-write or write-only instance properties and fields of the attribute type.

When specifying an attribute of an element, positional parameters are mandatory and named parameters are optional. Since the parameters used to specify an attribute are evaluated at compile time, they are generally limited to constant expressions.

Attribute Targets

Implicitly, the target of an attribute is the code element it immediately precedes, such as with the attributes we have covered so far. Sometimes it is necessary to explicitly specify that the attribute applies to particular target.

Here is an example of using the CLSCompliant attribute to specify the level of CLS compliance for an entire assembly:

[assembly:CLSCompliant(true)]

Specifying Multiple Attributes

Multiple attributes can be specified for a single code code element. Each attribute can be listed within the same pair of square brackets (separated by a comma), in separate pairs of square brackets, or in any combination of the two.

Consequently, the following three examples are semantically identical:

[Serializable, Obsolete, CLSCompliant(false)]
public class Bar {...}
  
[Serializable] 
[Obsolete] 
[CLSCompliant(false)]
public class Bar {...}
  
[Serializable, Obsolete] 
[CLSCompliant(false)]
public class Bar {...}

Get C# in a Nutshell now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.