In .NET, you can annotate components, types, and their members with attributes. An attribute’s purpose is to control or modify the behavior of a framework, a tool, the compiler, or the CLR. For example, in Chapter 1, I showed a class annotated with the
[TestClass] attribute. This told a unit testing framework that the annotated class contains some tests to be run as part of a test suite.
Attributes are passive containers of information that do nothing on their own. To draw an analogy with the physical world, if you print out a shipping label containing destination and tracking information and attach it to a package, that label will not in itself cause the package to make its way to a destination. Such a label is useful only once the package is in the hands of a shipping company. When the company picks up your parcel, it’ll expect to find the label, and will use it to work out how to route your package. So the label is important, but ultimately, its only job is to provide information that some system requires. .NET attributes work the same way—they have an effect only if something goes looking for them. Some attributes are handled by the CLR or the compiler, but these are in the minority. The majority of attributes are consumed by frameworks, libraries, tools (such as a unit test runner), or your own code.
To avoid having to introduce an extra set of concepts into the type system, .NET models attributes as instances of .NET types. To ...