only for RuBoard - do not distribute or recompile Previous Section Next Section

2.16 Attributes

Syntax:

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

Attributes are language constructs that can decorate code elements (e.g., 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 that it derives from, or a parameter can specify how its values are to be passed with modifiers such as the ref modifier in C#. The limitation of this approach is that you can only associate information with code elements using the predefined constructs that the language itself provides.

Attributes allow programmers to add to 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 is more flexible than requiring the language to have special syntax for serialization.

2.16.1 Attribute Classes

An attribute is defined by a class that inherits (directly or indirectly) from the abstract class System.Attribute. When specifying an attribute on an element, the attribute name is the name of the type. By convention the derived type name ends with the word "Attribute", but this suffix isn't required.

In this example we specify that the Foo class is 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 typename, as follows:

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

The preceding two examples that use the Serializable attribute are semantically identical.

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

2.16.2 Named and Positional Parameters

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

In this next example, we use the WebPermission attribute to specify that methods in class Foo cannot make web connections to any URL starting with http://www.oreilly.com/. This attribute allows you to include parameters that specify a security action and a URL:

[WebPermission(SecurityAction.Deny, 
    ConnectPattern="http://www.oreilly.com/.*")]
public class Foo {...}

Attribute parameters fall into one of two categories: positional and named parameters. In the preceding example, SecurityAction.Deny is a positional parameter, and ConnectPattern="http://www.oreilly.com/.*" is a named parameter.

The positional parameters for an attribute correspond to the parameters passed to one of 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 on the attribute type.

Since the parameters used when specifying an attribute are evaluated at compile time, they are generally limited to constant expressions.

2.16.3 Explicitly Specifying Attribute Targets

Implicitly, the target of an attribute is the code element it immediately precedes. However, sometimes it is necessary to explicitly specify that the attribute applies to a particular target. The possible targets are assembly, module, type, method, property, field, param, event, and return.

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

[assembly:CLSCompliant(true)]

2.16.4 Specifying Multiple Attributes

You can specify multiple attributes on a single 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 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 {...}
only for RuBoard - do not distribute or recompile Previous Section Next Section