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 anum 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:
public static string GetPropertyValue<T>(this Enum value, string AttributeProperty)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
T[] atts = fi.GetCustomAttributes(typeof(T), false) as T[];
if (atts.Length == 0)
return string.Empty;
PropertyInfo pi = atts[0].GetType().GetProperty(AttributeProperty);
if (pi == null)
throw new ArgumentException(String.Format("{0} is not a valid property name.", AttributeProperty));
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. Also remember to please vote.
Thanks!
History
2010-08-16 - Version 1.0