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…