This is an advanced sequel to C#: Enums and Strings Are Friends. One of particularly interesting features of an enum is the possibility of extending its values with attributes.

  1. public enum Digits  
  2.     {  
  3.         [Arabic("1")]  
  4.         [Roman("I")]  
  5.         One=1,  
  6.         [Arabic("2")]  
  7.         [Roman("II")]  
  8.         Two,  
  9.         [Arabic("3")]  
  10.         [Roman("III")]  
  11.         Three  
  12.     }  
These values can be obtained using .NET reflection mechanism. .NET already defines a lot of useful attributes such as Description, DisplayName, DefaultValue.

On top of that you are able to derive your custom attributes from the Attribute class. By adding properties to this class you can attach a plethora of information to each value of an enum.
  1. [AttributeUsage(AttributeTargets.Field)]  
  2. public class RomanAttribute : Attribute  
  3. {  
  4.     private readonly string _digit;  
  5.   
  6.     public string Digit  
  7.     {  
  8.         get { return _digit; }  
  9.     }  
  10.   
  11.     public RomanAttribute(string title)  // url is a positional parameter  
  12.     {  
  13.         _digit = title;  
  14.     }  
  15. }  
Wouldn't it be nice if we could read value of any property of any attribute straight off enum value? The problem with this concept is ... properties of different attributes have different names. For example: DescriptionAttribute has property named Description, and DisplayNameAttribute has property named DisplayName.

Luckily we live in the age of generics and reflections. So reading these properties no longer requires hard coded attribute type and target property. You can simply pass attribute type, property type, property name and enum to a function and let reflection do its business.

  1. // Read [Description] attribute.  
  2. Enum e = Days.Sat;  
  3. string s = e.GetAttributeProperty<DescriptionAttribute, string>("Description");  
  4. Console.WriteLine("Description is {0}", s);  
  5. // Read [DisplayName ] attribute.  
  6. s = e.GetAttributeProperty<DisplayNameAttribute, string>("DisplayName");  
  7. Console.WriteLine("Display name is {0}", s);  
  8. // Find enum value based on [Description].  
  9. Enum ef = e.FindEnumValueByAttributeProperty<DescriptionAttribute, string>("Description","Friday");  
All that is left is to write these two conversion functions.
  1. public static class EnumEx  
  2. {  
  3.     #region Enum Extensions  
  4.     public static PT GetAttributeProperty<AT, PT>(this Enum this_, string propertyName)  
  5.         where AT : Attribute  
  6.         where PT : class  
  7.     {  
  8.         // First get all attributes of type A.  
  9.         AT[] attributes =   
  10.             (this_.GetType().GetField(this_.ToString())).GetCustomAttributes(typeof(AT), falseas AT[];  
  11.   
  12.         if (attributes == null || attributes.Length == 0) // Null or can't cast?  
  13.             return null;  
  14.         else   
  15.         { // We have something.  
  16.             AT a = attributes[0];  
  17.             PropertyInfo pi = a.GetType().GetProperty(propertyName);  
  18.             if (pi != null)  
  19.             {  
  20.                 PT result = pi.GetValue(a, nullas PT;  
  21.                 return result;  
  22.             }  
  23.             else  
  24.                 return null;  
  25.         }  
  26.     }  
  27.   
  28.     public static Enum FindEnumValueByAttributeProperty<AT, PT>(this Enum this_, string propertyName, PT propertyValue)  
  29.         where AT : Attribute  
  30.         where PT : class, IComparable  
  31.     {  
  32.         // First get all enum values.  
  33.         Array enums = Enum.GetValues(this_.GetType());  
  34.         foreach (Enum e in enums)  
  35.         {  
  36.             PT p = e.GetAttributeProperty<AT, PT>(propertyName);  
  37.   
  38.             if (p!=null && p.Equals(propertyValue))  
  39.                 return e;  
  40.         }  
  41.         return null;  
  42.     }  
  43.     #endregion // Enum Extensions  
  44. }  
UPDATE: It seems like the usage of < and > symbols in code corrupted the listings. Fixed it.

1 comment(s) :

UPDATE: It seems like the usage of larger then and smaller then symbols in code corrupted the listings. Fixed it.

2:47 AM  

Newer Post Older Post Home

Blogger Syntax Highliter