Defining Data Outside the CodeThere is one last place where we can put data that defines our code: in a configuration file. This is nothing new. Long-time Windows developers have used INI files to store application-related information like user preferences, FTP site locations, and so on. Now it's conceivable that you could store metadata in configuration files. For example, here's what a configuration file would look like if we needed to state that BadCountry was obsolete: <BadCountry> <Metadata> <Obsolete CausesError="True"/> </Metadata> </BadCountry> The runtime would need to look up the information in the configuration file whenever a serialization request was made to make sure that the designer of the class allows its instances to be persisted. However, there are problems with this approach. First, with the metadata outside the code base, you now have an installation issue. Having the metadata in an XML file means that you must ship two files to the client. When the metadata is in the assembly, you need to ship only one file. This may not sound like a big deal, but at least with the one-file approach (assembly-only), you know the metadata is there when the assembly is there. Another problem is with metadata inheritance. As you'll see in the "Attribute Targets" section later in this chapter, as well as the "Inheritance and Custom Attributes" section in Chapter 4, you can set up attributes so that their use on a base class will also affect subclasses. You could do this with configuration files as well, but this kind of behavior is not designed into .NET. Code that acts on metadata would need to consider the lookup of the information within a base class; this is automatically taken care of through the design of attributes in .NET.The bigger issue is that external metadata can be adjusted by a client with relative ease. Would you want someone to make a class that was obsolete relevant again? What about making a class serializable when it was never intended to be saved to disk? When the metadata is in the assembly, it's much harder for someone to change that metadata. The intentions of the designer have a better chance of being preserved when they're embedded within the compiler's output.NOTE Granted, we're not dealing with reverse-engineering scenarios here. Someone who is savvy enough with ILDasm and CIL could make an obsolete class nonobsolete rather easily. There are countermeasures to reverse-engineering, but that discussion goes wellbeyond the topic at hand.Don't get us wrong-configuration files can be useful, especially when they define values that are used by the code and may change after the code is compiled. But configuration files are not appropriate when they define design characteristics of the class itself. Attributes are tightly coupled to the element that they are associated with, which is an essential feature of metadata. You've now seen where attributes can be used effectively. Now it's time to see how attributes are used in C#.