BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Reflection
/NET 1.1+

Creating Custom Attributes

The twenty-second and final part of the Reflection tutorial describes the creation and application of custom attributes. It also explains how those attributes can be configured to ensure that they are applied and inherited correctly.

Custom Attributes

In the previous article in this series we looked at the use of standard .NET framework attributes and how reflection could be used to determine which attributes have been applied to assemblies, types and members. Furthermore, we saw how the attributes could be retrieved at run time and their properties accessed. This allows you to base the behaviour of code upon the attributes applied to it.

In this final part of the tutorial we will look at how you can create your own attributes, apply them and reflect over their details at run time. This can be a very powerful tool, allowing you to simplify some types of code and give behaviour to types and members declaratively. To demonstrate this we'll start by looking at how custom attributes are created and applied, beginning with simple attributes before adding properties and configuration. We'll then create an example base class that reflects over the attributes of its subclasses to determine the behaviour of their ToString methods.

In the article we'll be using types from the System.Reflection namespace, so include the following using directive when executing the example code:

using System.Reflection;

Creating Attributes

Custom attributes are simply classes that inherit from the Attribute class. For the simplest attributes, where you will only need to know whether or not it has been applied to some code, this inheritance is enough. No code needs to be added to the attribute's body.

The following sample code shows such an attribute. This is the "Data" attribute, which could be used to indicate that a class represents a row of information in a database. Note that the class has the suffix, "Attribute". This is a naming convention for attributes that you should follow. The suffix is not required when applying the attribute.

public class DataAttribute : Attribute { }

We can apply the custom attribute in the same manner as any other, as shown below:

[Data]
public class Person
{
    public string Name { get; set; }
}

Once applied, you can use the attribute techniques discussed earlier in the tutorial to reflect over them. For example, with our simple attribute we might want only to know that it has been applied to a class. The code below checks if it is defined for the Person class:

Type type = typeof(Person);
bool isData = Attribute.IsDefined(type, typeof(DataAttribute)); // true

Adding Attribute Properties

Many of the standard .NET framework attributes are configurable, requiring some values to be provided when applying the attributes and allowing optional values that are initialised in the code with a named parameter. You can add this type of information to your own attributes by adding properties to the custom attribute's class.

Let's add a simple string property to our Data attribute to try this. The property below specifies the name of a database table. This could be used to link objects of types that have the attribute to the database table in which they should be stored. The class also includes a constructor that forces you to provide the Table value. It is good practice to include a constructor that sets the values of required properties to ensure that they are not omitted when used.

NB: The code uses an automatically implemented property. If you are using .NET 2.0 or earlier, you must expand this into a full property declaration with a backing store field.

public class DataAttribute : Attribute 
{
    public DataAttribute(string table)
    {
        Table = table;
    }

    public string Table { get; set; }
}

We now need to update the attribute for the Person class to include a value for the Table property.

[Data("People")]
public class Person
{
    public string Name { get; set; }
}

To extract information from the property using reflection we need to get the attribute, cast it to the correct type and read the property, as in the following code:

Type type = typeof(Person);
object[] attributes = type.GetCustomAttributes(typeof(DataAttribute), false);
DataAttribute attr = attributes[0] as DataAttribute;
Console.WriteLine(attr.Table);

/* OUTPUT

People

*/
27 August 2012