Helper class for working with 'extended' enums using StringValueAttribute attributes.
Namespace:
CA.Common.AttributesAssembly: CA.Common (in CA.Common.dll) Version: 1.0.0.0 (1.0.0.0)
Remarks
source code:
//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
//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 } }