Tagging Classes With Attributes

Saturday, January 16 2010

This past week, I wrote a custom C# Attribute for the first time. It was an attribute designed to be applied to classes to designate a particular, well, attribute of that class. It did not have any properties or methods in it: The attribute strictly served as what I’m interpreting as an attribute on a particular class.

[AttributeUsage(AttributeTargets.Class)]
public class McDonaldsAttribute : Attribute { }

In this example, I’m going to apply [McDonalds] only to whatever food is served at McDonalds.

public abstract class Food { }
 
/*...*/
 
[McDonalds]
public class Cheeseburger : Food { }
 
/*...*/
 
public class Pizza : Food { }

Here, Cheeseburger has the McDonalds attribute while Pizza does not. After all, McDonalds does not serve pizza. Not yet, anyway.

Now I can exploit this attribute usage in other classes:

public class RestaurantSelector
{
    public Restaurant SelectRestaurant(Food foodServedAtRestaurant)
    {
        if (foodServedAtRestaurant.GetType()
            .IsDefined(typeof(McDonaldsAttribute), false))
        {
            return new McDonaldsRestaurant();
        }
    }
}

I can decorate any Food class I desire with the McDonalds attribute, and when I give those classes that attribute the RestaurantSelector will know which Restaurant to select. I can see now, however, that using GetType().IsDefined() to check for attributes is a bit cumbersome. I’d say an extension method is in order:

public static class ObjectExtensions
{
    public static bool HasAttribute(this object objectToCheck, Type attribute)
    {
        return objectToCheck.GetType().IsDefined(attribute, false);
    }
}

Now this is just a sketched-out method, and isn’t by any means perfect. I could create an overload to pass in the boolean parameter there. It could also check to make sure that the Type passed in is an actual Attribute type. ObjectExtensions isn’t exactly the best name for the class either. Despite these faults, I have encapsulated the check for attributes on a class into a simple extension method:

if(someObject.HasAttribute(typeof(McDonaldsAttribute)))
{
    // someObject has McDonalds attribute.
}
Now checking for attributes is simple, and I can sleep better knowing that I’ve removed (future) instances of code duplication.
 
EDIT: Turns out that this isn't quite the Decorator Pattern after all. Special thanks to Brendan for his assistance!