In Effective Extensions – Extending Types in C# we covered how to use a few useful methods to extend Types in C#. This time we are going to look at extending enums in C#.
Q: So, why extend enums?
A: Because they are typically inflexible and require some funky casting to get what you need from simple data types such as strings and integers.
Here is our example enum:
/// <summary> /// Thread-state type. /// </summary> public enum ThreadStateType { [Description("Initialized")] Started = 0, [Description("Ready")] Waiting = 1, [Description("Running")] Processor = 2, [Description("Standby")] PreProcessor = 3, [Description("Terminated")] Ended = 4, [Description("Wait")] NotReady = 5, [Description("Transition")] WaitingForResource = 6, [Description("Unknown")] UndeterminedState = 7 }
You will notice that each value in the enum has a Description attribute. This can be extremely effective in allowing us to get a more meaningful value or message from an enum without having to do complex conversions. Let’s look at those.
ToDescription
Q: So, how do we get those descriptions?
A: With a “ToDescription” extension like the one below:
/// <summary> /// Return the description tied to an enum. /// </summary> /// <param name="en">The en.</param> /// <returns></returns> public static string ToDescription(this Enum en) { // ext method var type = en.GetType(); var memberInfo = type.GetMember(en.ToString()); // No members if (memberInfo.Length <= 0) return en.ToString(); // Get attributes var attributes = memberInfo.First().GetCustomAttributes(typeof(DescriptionAttribute), false); // Assess attributes return attributes.Length > 0 ? ((DescriptionAttribute)attributes.First()).Description : en.ToString(); }
It’s not pretty, but extremely useful. It can be used like this:
// Get enum ThreadStateType myType = ThreadStateType.Processor; // Get description from enum Console.Write(myType.ToDescription()); // Prints: Running
GetEnumFromDescription
Q: Okay, so what if I only have the enum description and want the enum value back?
A: We can do that too:
/// <summary> /// Process a string and return an Enum value that has that description. /// </summary> /// <param name="value">string representing the enum's description</param> /// <typeparam name="T">The type of Enum</typeparam> /// <returns>Enum value corresponding to the string description</returns> /// <exception cref="ArgumentException">T must be an enumerated type</exception> public static T GetEnumFromDescription<T>(string value) where T : struct, IConvertible { // Must be an enum if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type"); // Evaluate foreach (var val in Enum.GetValues(typeof(T))) { if (((Enum)val).ToDescription() != value) continue; if (val != null) return ((T)val); } // Return return default(T); }
And that can be used like this:
// Use GetEnumFromDescription to get an enum from a string representing its description. ThreadStateType myType = EnumExtensions.GetEnumFromDescription<ThreadStateType>("Running"); // Returns: ThreadStateType.Processor
ToEnum
Q: And what if I have a string representing the name of the enum and want it’s value?
A: This isn’t typical unless you did a ToString() to the enum, but we can convert that back too:
/// <summary> /// Process a string and return an Enum value for it /// </summary> /// <param name="str">string representing the enum</param> /// <typeparam name="T">The type of Enum</typeparam> /// <returns>Enum value corresponding to the string value</returns> /// <exception cref="ArgumentException">T must be an enumerated type</exception> public static T ToEnum<T>(this String str) where T : struct, IConvertible { if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type"); foreach (var value in Enum.GetValues(typeof(T))) { if (value.ToString() == str) return (T)value; } return default(T); }
An example of this would be:
// Get the "Processor" enum from the string "Processor" ThreadStateType myType = ("Processor").ToEnum<ThreadStateType>(); // Returns: ThreadStateType.Processor
And that’s really all there is to it. These are simple extensions for otherwise complex derivations but it should help you get over your fear of using enums in C#.
Until next time…