Free mag vol1 | Page 643

CHAPTER 15  TYPE REFLECTION, LATE BINDING, AND ATTRIBUTE-BASED PROGRAMMING In some cases, this is exactly the behavior you require. Other times, however, you may want to build a custom attribute that can be applied only to select code elements. If you wish to constrain the scope of a custom attribute, you will need to apply the [AttributeUsage] attribute on the definition of your custom attribute. The [AttributeUsage] attribute allows you to supply any combination of values (via an OR operation) from the AttributeTargets enumeration, like so: // This enumeration defines the possible targets of an attribute. public enum AttributeTargets { All, Assembly, Class, Constructor, Delegate, Enum, Event, Field, GenericParameter, Interface, Method, Module, Parameter, Property, ReturnValue, Struct } Furthermore, [AttributeUsage] also allows you to optionally set a named property (AllowMultiple) that specifies whether the attribute can be applied more than once on the same item (the default is false). As well, [AttributeUsage] allows you to establish whether the attribute should be inherited by derived classes using the Inherited named property (the default is true). To establish that the [VehicleDescription] attribute can be applied only once on a class or structure, you can update the VehicleDescriptionAttribute definition as follows: // This time, we are using the AttributeUsage attribute // to annotate our custom attribute. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false)] public sealed class VehicleDescriptionAttribute : System.Attribute { ... } With this, if a developer attempted to apply the [VehicleDescription] attribute on anything other than a class or structure, he or she is issued a compile-time error. Assembly-Level Attributes It is also possible to apply attributes on all types within a given assembly using the [assembly:] tag. For example, assume you wish to ensure that every public member of every public type defined within your assembly is CLS compliant.  Note Chapter 1 mentioned the role of CLS-compliant assemblies. Recall that a CLS-compliant assembly can be used by all .NET programming languages out of the box. If you create public members of public types, which expose non–CLS compliant programming constructs (such as unsigned data or pointer parameters), other .NET languages may not be able to use your functionality. Therefore, if you are building C# code libraries that need to be used by a wide variety of .NET languages, checking for CLS compliance is a must. 585