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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /// <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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /// <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:
1 2 3 4 5 6 7 | // 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /// <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:
1 2 3 4 | // 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /// <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:
1 2 3 4 | // 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…