Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

Using Attributes, Reflection and Generics To Increase The Usability Of Enums

5.00/5 (3 votes)
22 Aug 2010CPOL2 min read 13.8K  
Combining custom attributes, reflection and generics to maximize the use of enum in a system.

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:


/// <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. Also remember to please vote.


Thanks!


History


2010-08-16 - Version 1.0

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)