Something to note

Note: This code was done a couple of years back as an tip/trick for Code Project. The code here can be simplified quite a bit by using the latest .NET features such as lamda expressions, but I still wanted to add it here as a reference. Some of the concepts still hold valid, and can be used for other applications. Please be kind, and enjoy.

Introduction

This article explains a solution that I came up with to make the most of the enums we were using in one of our systems beings developed. The solution makes use of custom attributes, reflection and generics to maximise our use of enums.

Background

At work we are busy doing a new project that makes use of a lot of enums, of different types. As everyone know, enums can make life much easier when it comes to coding, and this project was no different.

During the development the need to associate additional data with the enums became clear. This article will describe the methods we implemented to overcome this obstacle.

Building blocks of the solution

Most people have seen the examples of giving a EnumDescription attribute to each enum value, which is then reflected to return a human-friendly description of the required enum value.

An example of this scenario would be:

public enum Institution
{
[EnumDescription(“Bank A”)]
BankA,

[EnumDescription (“Shop B”)]
ShopB,

[Description(“Library C”)]
LibraryC
}

Our solution is based on a similar concept, but expanded it to include not only description on the attribute, but other needed properties as well. In our project we created several new custom attributes, that can be used to decorate the enums as needed, depending on the data we need to associate with it.

For example:

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public sealed class InstituteAttribute: Attribute
{
	public InstituteAttribute(string Desc, string Phone)
	{
		Description = Desc;
		Telephone=Phone;
	}	

	public string Description {get;set;}
	public string Telephone {get;set;}
}

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public sealed class AddressAttribute: Attribute
{
	public AddressAttribute (string Add1, string Add2, string City, string ZipCode)
	{
		this.Address1 = Add1;
		this.Address2 = Add2;
		this.City = City;
		this.ZipCode = ZipCode;
	}	

	public string Address1 {get;set;}
	public string Address2 {get;set;}
	public string City {get;set;}
	public string ZipCode {get;set;}
}

To get the values of these attributes, and it’s properties we can easily apply the same concept we use in “EnumDescription” situation, but this is not very flexible, since we have to know what type we are working on, and which properties exist.

Usage example of these new attributes:

public enum Institution
{
	[Institute (“Bank A”,  ”(856) 745-1546”)]
	[Address(“123 Street”, “Some town”, “Some City” , ”1452”)] 
	BankA,

	[Institute (“Shop B”,  “(012) 154-1456”)]
	ShopB,

	[Institute (“Library C”,  “(123) 147-4567”)]
	LibraryC
}

To make use of this information we created a helper extension method that can be used to reflect on any type of attribute, to get any property on that attribute. Below is the extension method to solve this issue.

Using the code

Short summary of what the extension method below does:

  • Get the enum value and it’s info (FieldInfo)
  • Get all attributes of type T decorating the enum value (there can only at most 1, since we set the AllowMultiple property to false when we created the custom attribute
  • If there are any attributes of type T, run through all the properties in that type T to try and find the desired property that was specified
  • If the specified property cannot be found, throw an exception (can easily be modifed to return a default string value)
  • If the specified property is found, get the value, and return it.
/// <summary>
/// Use this extension method to obtain any property in an attribute used to decorate the fields of an Enum
/// </summary>
/// <typeparam name="T">Type of attribute containing the wanted properties</typeparam>
/// <param name="value">This will be the Enum value</param>
/// <param name="AttributeProperty">The property of the specified attribute that must be returned.</param>
/// <returns>The property value specified</returns>
public static string GetPropertyValue<T>(this Enum value, string AttributeProperty)
{
	//Get the enum value
    FieldInfo fi = value.GetType().GetField(value.ToString());

	T[] atts = fi.GetCustomAttributes(typeof(T), false) as T[];

    //if there is any attributes of the specified type
    if (atts.Length == 0)
    	return string.Empty;

    //find propertyname
    PropertyInfo pi = atts[0].GetType().GetProperty(AttributeProperty);
    if (pi == null)
		throw new ArgumentException(String.Format("{0} is not a valid property name.", AttributeProperty));

    //return value of property
    return pi.GetValue(atts[0],null).ToString();
}

Now that we have this extension method on place, we can easily get the data we require from the enums.

Example:

string shopPhone = Institution.ShopB.GetPropertyValue<InstituteAttribute>(Telephone);

The above statement will call the GetPropertyValue extension method on the ShopB enum value, and return the value of the “Telephone” property in the “Institute” attribute used to decorate enum value ShopB.

Feedback

I hope some of you find this helpful, and please do not hesitate to leave any feedback, improvements, or other.

Thanks!