Helper class for working with 'extended' enums using StringValueAttribute attributes.

Namespace:  CA.Common.Attributes
Assembly:  CA.Common (in CA.Common.dll) Version: 1.0.0.0 (1.0.0.0)

Remarks

source code:

CopyC#
//Source code from the Code Associate C# code library, Full documentation and latest updates can be found
//@ http://www.codeassociate.com/caapi/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

namespace CA.Common.Attributes
{
    public static class StringEnum
    {

        private static Hashtable _stringValues = new Hashtable();

        private static void ValidateAsEnumClass(Type enumType)
        {
            if (!enumType.IsEnum)
                throw new ArgumentException(String.Format("Supplied type must be an Enum.  Type was {0}", enumType));
        }

        public static string GetStringValue(Enum value)
        {
            string output = null;
            Type type = value.GetType();

            if (_stringValues != null && _stringValues.ContainsKey(value))
            {
                StringValueAttribute sv = (StringValueAttribute)_stringValues[value];
                if (sv != null)
                    output = sv.Value;
            }
            else
            {
                //Look for our 'StringValueAttribute' in the field's custom attributes
                FieldInfo fi = type.GetField(value.ToString());
                StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
                if (attrs != null && attrs.Length > 0)
                {
                    // lock the Hash table while inserting new data. 
                    lock (_stringValues)
                    {
                        _stringValues.Add(value, attrs[0]);
                    }
                    output = attrs[0].Value;
                }

            }
            return output;
        }

        public static object Parse(Type type, string stringValue)
        {
            return Parse(type, stringValue, false);
        }

        public static object Parse(Type type, string stringValue, bool ignoreCase)
        {
            object output = null;
            string enumStringValue = null;

            ValidateAsEnumClass(type);

            //Look for our string value associated with fields in this enum
            foreach (FieldInfo fi in type.GetFields())
            {
                //Check for our custom attribute
                StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
                if (attrs != null && attrs.Length > 0)
                    enumStringValue = attrs[0].Value;

                //Check for equality then select actual enum value.
                if (string.Compare(enumStringValue, stringValue, ignoreCase) == 0)
                {
                    output = Enum.Parse(type, fi.Name);
                    break;
                }
            }

            return output;
        }

        public static bool IsStringDefined(Type enumType, string stringValue)
        {
            return Parse(enumType, stringValue) != null;
        }

        public static bool IsStringDefined(Type enumType, string stringValue, bool ignoreCase)
        {
            return Parse(enumType, stringValue, ignoreCase) != null;
        }

        public static IList<StringEnumContainer> GetListValues(Type enumType)
        {
           ValidateAsEnumClass(enumType);
           Type underlyingType = Enum.GetUnderlyingType(enumType);

            List<StringEnumContainer> result = new List<StringEnumContainer>();

            foreach (FieldInfo fi in enumType.GetFields())
            {
                if (fi.FieldType.FullName != underlyingType.FullName)
                {
                    StringEnumContainer ListEntry = new StringEnumContainer();
                    //Check for the StringValueAttribute custom attribute
                    StringValueAttribute[] attrs =
                        fi.GetCustomAttributes(typeof (StringValueAttribute), false) as StringValueAttribute[];
                    ListEntry.EnumIntvalue = (int)Convert.ChangeType(Enum.Parse(enumType, fi.Name), underlyingType);
                    ListEntry.EnumCodevalue = (Enum)Enum.Parse(enumType, fi.Name);

                    if (attrs != null && attrs.Length > 0)
                        ListEntry.EnumStringvalue = attrs[0].Value;
                    else
                        ListEntry.EnumStringvalue = null; // use the default;

                    result.Add(ListEntry);
                }
            }
            return result;
        }

        public static StringEnumDataTable GetEnumValuesAsDataTable(Type enumType)
        {
            // get the IList first to avoid duplicate logic
            IList<StringEnumContainer> list = StringEnum.GetListValues(enumType);
            // now create a data table to hold the data
            StringEnumDataTable result = new StringEnumDataTable();
            // now loop though all elements in the list inserting them into the table. 
            foreach (StringEnumContainer obj in list)
            {
                result.AddRowFromContainer(obj);
            }
            return result;
        }
    }    
}

Examples

Example Usage using unit tests showing full usage. For more targeted examples see the specific methods

Examples

CopyC#
//Source code from the Code Associate C# code library, Full documentation and latest updates can be found
//@ http://www.codeassociate.com/caapi/
using System;
using System.Collections.Generic;
using System.Data;
using NUnit.Framework;
using System.Diagnostics;
using CA.Common.Attributes;

namespace CA.Common.UnitTest.Attributes
{
-    #region ExampleStringValueAttribute
     public enum MenuItemType
     {
         [StringValue("Header for a Menu")]
         Header,
         [StringValue("All odd Menu Items")]
         Item,
         [StringValue("All even Menu Items")]
         AlternatingItem,
         [StringValue("Footer for a Menu")]
         Footer
     }
     #endregion ExampleStringValueAttribute


-    #region ExampleStringValueTestEnumValues
 
     public enum TestEnumValues
     {
         [StringValue("A non valid .NET name")]
         NonValidDotNetName = 1,
 
         EnumValueWithNoStringValue = 2,
 
         EnumValueWithNoNumber
     }
 
     #endregion ExampleStringValueAttribute


    [TestFixture]
    public class StringEnum_UnitTests
    {
-        #region tests
 
-        #region BasicStringEnumTests
         [Test]
         public void CheckStringToEnumWorksWithValidStringValue()
         {
             // test to get the value string value for TestEnumValues.NonValidDotNetName
             string stringEnumValue = StringEnum.GetStringValue(TestEnumValues.NonValidDotNetName);
             // the expected result is the value defined in the StringValue attribute which is hardcoded for testing
             Assert.AreEqual("A non valid .NET name", stringEnumValue);
 
             // Now we should convert back the stringEnumValue to an enum This shows that we can go both ways
             TestEnumValues convertBack = (TestEnumValues)StringEnum.Parse(typeof (TestEnumValues), stringEnumValue);
             Assert.AreEqual(TestEnumValues.NonValidDotNetName,convertBack);
 
             // Do the same as above however this time ignore the case of the string by changing the value to upper case and specifying the boolean to be case insensitive 
             convertBack = (TestEnumValues)StringEnum.Parse(typeof (TestEnumValues), stringEnumValue.ToUpper(), true);
             Assert.AreEqual(TestEnumValues.NonValidDotNetName,convertBack);
 
             // test to get the value string value for TestEnumValues.NonValidDotNetName this time it should get the value from cache and not using reflection however the result should be the same
             stringEnumValue = StringEnum.GetStringValue(TestEnumValues.NonValidDotNetName);
             // the expected result is the value defined in the StringValue attribute which is hardcoded for testing
             Assert.AreEqual("A non valid .NET name", stringEnumValue);
 
             bool isdefined = StringEnum.IsStringDefined(typeof (TestEnumValues), stringEnumValue);
             Assert.AreEqual(true, isdefined);
 
             isdefined = StringEnum.IsStringDefined(typeof(TestEnumValues), stringEnumValue.ToLower());
             Assert.AreEqual(false, isdefined);
 
             isdefined = StringEnum.IsStringDefined(typeof(TestEnumValues), stringEnumValue.ToLower(), true);
             Assert.AreEqual(true, isdefined);            
         }
         #endregion
 
-        #region ExampleStringValueAttribute2
         [Test]
         public void CheckStringToEnumWorksWithMenuItemType()
         {
             // will extract the value string value from MenuItemType.Item into the string variable stringEnumValue
             string stringEnumValue = StringEnum.GetStringValue(MenuItemType.Item);
             // the expected result is the value defined in the MenuItemType.Item attribute which is hardcoded for testing
             Assert.AreEqual("All odd Menu Items", stringEnumValue);
         }
         #endregion ExampleStringValueAttribute2
 
 
         [Test]
         public void CheckStringToEnumWorksWithNonValidStringValue()
         {
             // check tht if a StringAttrubuteValue is not defined it will return null
             string stringEnumValue = StringEnum.GetStringValue(TestEnumValues.EnumValueWithNoStringValue);
             Assert.AreEqual(null, stringEnumValue);
         }
 
-        #region CheckStringToEnumAsBindableList
         [Test]
         public void CheckStringToEnumAsBindableList()
         {
             // Test getting a 'bindable' list of enums for a given typeOfEnum. This is useful for binding to a UI element. The returned elements are a IList<StringEnumContainter>   
             IList<StringEnumContainer> list = StringEnum.GetListValues(typeof(TestEnumValues));
             foreach (StringEnumContainer obj in list)
             {
                 Trace.WriteLine(obj.EnumIntvalue.ToString());
                 Trace.WriteLine(obj.EnumCodevalue.ToString());
                 Trace.WriteLine(obj.EnumStringvalue);
             }
         }
         #endregion
 
-        #region CheckStringToEnumAsDataTable
         [Test]
         public void CheckStringToEnumAsDataTable()
         {
             DataTable dt = StringEnum.GetEnumValuesAsDataTable(typeof(TestEnumValues));
             foreach (DataRow dr in dt.Rows)
             {
                 Trace.WriteLine(string.Format("ID={0}", dr["ID"]));
                 Trace.WriteLine(string.Format("EnumCodeValue={0}", dr["EnumCodeValue"]));
                 Trace.WriteLine(string.Format("EnumStringValue={0}", dr["EnumStringValue"]));
             }
         }
         #endregion CheckStringToEnumAsDataTable
 
         [Test]
         public void TestRaiseErrorWithNonEnum()
         {
             try
             {
                 IList<StringEnumContainer> list = StringEnum.GetListValues(this.GetType());
             }
             catch(System.Exception ex)
             {
                 Assert.IsInstanceOfType(typeof (ArgumentException), ex);
             }
         }
         #endregion
    }
}

Inheritance Hierarchy

System..::.Object
  CA.Common.Attributes..::.StringEnum

See Also