Effective Extensions, Part 2 – Extending Enums in C#

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…

 
Comments

No comments yet.

Leave a Reply