The Joy of Custom Attributes

Created: January 21, 2016 Tagged As: .net, C#, Language Share:

If you are not familiar with them, attributes provide a form of runtime-level metadata. For instance, to allow an object to be serializable (e.g., persisted to a source other than RAM), the class needs to be marked with an attribute:

[Serializable] 
public class MySerializableClass { }

OK, so the.net runtime reads this and adds the logic needed to serialize this class. Big deal. Well it actually is, but that is not the point of this article.

While these built-in attributes are powerful and I use them quite a bit, I find that writing custom attributes offers even more!

Defining A Custom Attribute Example

Consider the example below that defines my custom attribute called ConfigurableAttribute and a very basic and arguable silly Mammal. 

public class ConfigurableAttribute : Attribute
{
}

public class Mammal
{
public Mammal()
{
EyeCount = 2;
IsWarmBlooded = true;
}

[Configurable]
public int EyeCount { get; set; }

public bool IsWarmBlooded { get; set; }

[Configurable]
public int LegCount { get; set; }

[Configurable]
public bool IsFurry { get; set; }

[Configurable]
public bool HasTail { get; set; }
}

You can see that the constructor sets the EyeCount to a default of 2 and IsWarmBlooded to true as that has to be the case. 

You will notice that I have decorated only some of the properties with my custom [Configurable] attribute moniker. Why? Because those are the only attributes that I want an end user to be able to configure with a UI that I am going to write.

Using a Custom Attribute

So how do I use this attribute? In this case, I want to find ONLY the properties that have this attribute defined. To do that, I would write code something similar to this:

Type t = typeof(Mammal);
foreach (PropertyInfo pi in t.GetProperties().Where(p => p.GetCustomAttribute<ConfigurableAttribute>() != null))
Console.WriteLine(pi.Name); 

The output will be:
EyeCount
LegCount
IsFurry
HasTail

Summary

While this isn't a very useful example, it does show the capabilities of custom attributes. Imagine using the ConfigurableAttribute and reading the PropertyInfo object for each returned property and creating a text box, check box, or numeric input box based on the property's type along with a label with the property's name to allow someone to enter values for each Configurable property! As the class changes, all you have to do is add a new property, decorate it with [Configurable] and suddenly your UI is updated as well - mind blown!