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 library 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 the 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 Visual Studio’s 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 ...