August 23, 2011

Enum and Description Attribute

Found this helper in this article EnumHelper - Getting a Friendly Description from an Enum by Grant Barrington, initially.
Found idea for the generic enum class here
Have refactored and merged them a little and added a couple of my own methods
    /// <summary>
    /// Not really an extension class but this is more readable than an extension class.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class Enum<T> 
        where T : struct // Cannot specify an enum here so narrow it down to a struct
    {
        /// <summary>
        /// Parse the given string into an enum value, ignores the case of the string
        /// </summary>
        /// <param name="value">string to parse, leading and trailing whitespace characters are removed</param>
        /// <returns>Enum value parsed from the string</returns>
        public static T Parse(string value)
        {
            if (false == typeof(T).IsEnum)
                throw new NotSupportedException(typeof(T).Name + " must be an Enum");

            return Enum<T>.Parse(value.Trim(), true);
        }

        /// <summary>
        /// Parse the given string into an enum value
        /// </summary>
        /// <param name="value">string to parse, leading and trailing whitespace characters are removed</param>
        /// <param name="ignoreCase">Whether to ignore the case of the letters in the string when parsing</param>
        /// <returns>Enum value parsed from the string</returns>
        public static T Parse(string value, bool ignoreCase)
        {
            if (false == typeof(T).IsEnum)
                throw new NotSupportedException(typeof(T).Name + " must be an Enum");

            return (T)Enum.Parse(typeof(T), value.Trim(), ignoreCase);
        }

        /// <summary>
        /// Try to parse the given string into an enum value, ignores the case of the string. Capture any exceptions
        /// </summary>
        /// <param name="value">string to parse, leading and trailing whitespace characters are removed</param>
        /// <param name="returnedValue">Enum value parsed from the string</param>
        /// <returns>true if the string was successfully parsed into a enum value of the given type</returns>
        public static bool TryParse(string value, out T returnedValue)
        {
            return Enum.TryParse<T>(value, true, out returnedValue);
        }

        /// <summary>
        /// Try to parse the given string into an enum value. Capture any exceptions
        /// </summary>
        /// <param name="value">string to parse, leading and trailing whitespace characters are removed</param>
        /// <param name="ignoreCase">Whether to ignore the case of the letters in the string when parsing</param>
        /// <param name="returnedValue">Enum value parsed from the string</param>
        /// <returns>true if the string was successfully parsed into a enum value of the given type</returns>
        public static bool TryParse(string value, bool ignoreCase, out T returnedValue)
        {
            return Enum.TryParse<T>(value, ignoreCase, out returnedValue);
        }

        /// <summary>
        /// Get the enum values of the given enum type
        /// </summary>
        /// <returns>Array of the enum values in the enum type</returns>
        public static Array GetValues()
        {
            if (false == typeof(T).IsEnum)
                throw new NotSupportedException(typeof(T).Name + " must be an Enum");

            return Enum.GetValues(typeof(T));
        }

        /// <summary>
        /// Returns first description attribute of the enum value or the enum value 
        /// itself as a string if no description attribute was found
        /// </summary>
        /// <param name="enumValue">An enum value in the given enum type</param>
        /// <returns>
        /// First description attribute found of the enum value or the enum value 
        /// itself as a string if no description attribute was found
        /// </returns>
        public static string GetAsString(T enumValue)
        {
            if (false == typeof(T).IsEnum)
                throw new NotSupportedException(typeof(T).Name + " must be an Enum");

            string res = GetFirstDescriptionAttribute(enumValue);
            if (string.IsNullOrEmpty(res))
                res = enumValue.ToString();
            return res;
        }

        /// <summary>
        /// Returns first description attribute of the enum value
        /// </summary>
        /// <param name="enumValue">An enum value in the given enum type</param>
        /// <returns>
        /// First description attribute found of the enum value or null if no description attribute was found
        /// </returns>
        public static string GetDescriptionAttribute(T enumValue)
        {
            if (false == typeof(T).IsEnum)
                throw new NotSupportedException(typeof(T).Name + " must be an Enum");

            Type type = enumValue.GetType();

            MemberInfo[] memInfo = type.GetMember(enumValue.ToString());

            if (memInfo != null && memInfo.Length > 0)
            {
                object[] attrs = memInfo[0].GetCustomAttributes(
                    typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0)
                {
                    return ((DescriptionAttribute)attrs[0]).Description;
                }
            }

            return null;
        }

 
    }
Now use the above helpers to demonstrate how to get the description attribute on an enum entry and how to get the best string form for an enum for entry into a listbox or something
public enum DescriptionsEnum
{
    [DescriptionAttribute("Add On")]
    AddOn,
    [DescriptionAttribute("Snap On")]
    SnapOn = 7,
    Adjacent = 2,
    Fixed = 12,
};

public void Test1()
{
    int asInt = 0;            
    foreach (var entry in Enum<DescriptionsEnum>.GetValues())
    {
        asInt = (int)entry;
        Console.WriteLine(asInt.ToString() + " " + 
            entry.ToString() + ":" + 
            Enum<DescriptionsEnum>.GetDescriptionAttribute((Enum)entry));
    }
    Console.WriteLine();
    foreach (var entry in Enum<DescriptionsEnum>.GetValues())
    {
        asInt = (int)entry;
        Console.WriteLine(asInt.ToString() + " " + 
            Enum<DescriptionsEnum>.GetAsString((Enum)entry));
    }
}
and the output of the test is
0 AddOn:Add On
2 Adjacent:
7 SnapOn:Snap On
12 Fixed:

0 Add On
2 Adjacent
7 Snap On
12 Fixed
There is also an interesting article on Enum: Binding to the Description Attribute by Deborah Kurata.
Using these helpers making something to bind to is much simpler:
Dictionary<string, int> bindToMe = new Dictionary<string, int>();
foreach (var entry in Enum.GetValues(typeof(DescriptionsEnum)))
{
    asInt = (int)entry;
    bindToMe.Add(EnumHelper.GetAsString((Enum)entry), asInt);
} 

No comments: