C Sharp

Defining Attributes

In the previous example, note that the syntax used to attach an attribute to a type or member looks a bit like the instantiation of a class. This is because an attribute is actually a class derived from the System.Attribute base class.

Now let's flesh out the RegistryKey attribute a little bit: -

public enum RegistryHives
{
    HKEY_CLASSES_ROOT,
    HKEY_CURRENT_USER,
    HKEY_LOCAL_MACHINE,
    HKEY_USERS,
    HKEY_CURRENT_CONFIG
}
public class RegistryKeyAttribute : Attribute
{
    public RegistryKeyAttribute(RegistryHives Hive, String ValueName)
    {
        this.Hive = Hive;
        this.ValueName = ValueName;
    }
    protected RegistryHives hive;
    public RegistryHives Hive
    {
        get { return hive; }
        set { hive = value; }
    }
    protected String valueName;
    public String ValueName
    {
        get { return valueName; }
        set { valueName = value; }
    }
}

What I've done here is add an enum for the different Registry types, a constructor for the attribute class (which takes a Registry type and a value name), and two properties for the Registry hive and value name. There's much more you can do when defining attributes, but at this point, because we know how to define and attach attributes, let's go ahead and learn how to query for attributes at run time. That way, we'll have a fully working example to play with. Once we've done that, we'll move on to some of the more advanced issues with defining and attaching attributes.

NOTE
Note that in the examples the attribute class names are appended with the word Attribute. However, when I then attach the attribute to a type or member, I don't include the Attribute suffix. This is a shortcut thrown in for free by the C# language designers. When the compiler sees that an attribute is being attached to a type or member, it will search for a System.Attribute derived class with the name of the attribute specified. If a class can't be located, the compiler will append Attribute to the specified attribute name and search for that. Therefore, it's common practice to define attribute class names as ending in Attribute and then to omit that part of the name.

Querying About Attributes

We know how to define an attribute by deriving it from System.Attribute and how to attach it to a type or member. Now what? How can we use attributes in code? In other words, how can we query a type or member as to the attributes (and its parameters) that have been attached? -

To query a type or member about its attached attributes, we must use reflection. Reflection is an advanced topic that's covered in Chapter 16, "Querying Metadata with Reflection," so I'll discuss only enough about it here to illustrate what's needed to retrieve attribute information at run time. If you want to learn more about reflection, refer to Chapter 16.

Reflection is a feature that allows you to dynamically determine at run time the type characteristics for an application. For example, you can use the .NET Framework Reflection APIs to iterate through the metadata for an entire assembly and produce a list of all classes, types, and methods that have been defined for that assembly. Let's look at some examples of attributes and how they would be queried using reflection.