C#: Enums and String Values

One of the biggest things that I've had a problem with C# is its complete, utter lack of string value enumerations.  Enums provide strongly typed domain values that make programming easier to manage.  However, since you can't include characters like wildcards, spaces, etc., this means that making a human readable enum a nearly impossible task.  Until now.  This takes a little more heavy lifting than I come to expect with the .Net framework, but is a relatively easy fix for what you get in return.  This is broken into two parts:
  1. Create the String value for the enum.
  2. Get the value out.

First things first, how to create a string value enum.  To do this we need to import the System.Reflection and System.ComponentModel into the class and to create a new enum as follows:

public enum IceCream
{
        [DescriptionAttribute("Chocolate Chip")]ChocolateChip,
        [DescriptionAttribute("Rocky Road")]RockyRoad,
        Vanilla
}

As you can see we define the enum just like we normally do, except we take advantage of C#'s DescriptionAttribute class.   What this does is allows us to bind a string attribute to the enum which normally only accepts  numerical type data.  Unlike other methods to do this, we don't break the enum paradigm.  If I had my druthers I would have liked to inherit from the Enum class itself, but that's not possible.

So, now that we've created our enum, how do we retrieve that value?  Next we create another class as outlined below:

public class EnumUtils
{
        public static string stringValueOf(Enum value)
        {
            FieldInfo fi = value.GetType().GetField(value.ToString());
            DescriptionAttribute[] attributes = (DescriptionAttribute[]) fi.GetCustomAttributes( typeof(DescriptionAttribute), false);
            if (attributes.Length > 0)
            {
                return attributes[0].Description;
            }
            else
            {
                return value.ToString();
            }
        }

        public static object enumValueOf(string value, Type enumType)
        {
            string[] names = Enum.GetNames(enumType);
            foreach (string name in names)
            {
                if (stringValueOf((Enum)Enum.Parse(enumType, name)).Equals(value))
                {
                    return Enum.Parse(enumType, name);
                }
            }

            throw new ArgumentException("The string is not a description or value of the specified enum.");
        }
}

What we do in the first method is use reflection to access the DescriptionAttribute that we created when we constructed the enum.  If the enum value doesn't have a DescriptionAttribute associated with it, we return the ToString() value of the enum itslef.  That way, enums like 'Vanilla' get returned as "Vanilla" instead of null.

The second method enumValueOf address the need to go from the string value to the enum itself.  This uses the Enum static methods to compare the string value to the list of enum values.  While this particular could be further optimized with caching, this sets up a basic, but useful string value enumeration.

Enjoy!

Print | posted on Friday, October 05, 2007 7:32 PM

Comments on this post

# re: C#: Enums and String Values

Requesting Gravatar...
Very Nice Work Man I love it


Thank you alot.
Left by Shouha on Jul 22, 2008 4:06 AM

# re: C#: Enums and String Values

Requesting Gravatar...
hey thanks for the great piece of code...it was really helpful for me today...
Left by jonathan parker on Oct 03, 2008 3:54 PM

# re: C#: Enums and String Values

Requesting Gravatar...
Give a example,please!Thanks.
Left by boy on Oct 27, 2008 9:48 PM

# re: C#: Enums and String Values

Requesting Gravatar...
Thanks for posting, Vb.net version of codes i posted below

mefeozer.wordpress.com/.../get-enum-values-as-s...
Left by M.Efe Ozer on Oct 31, 2008 10:09 AM

# re: C#: Enums and String Values

Requesting Gravatar...

I looked all over the internet for a solution such as yours:

Enum.Parse(enumType, name);


Thank you!
Left by Dirk Garner on Dec 09, 2008 12:48 PM

# re: C#: Enums and String Values

Requesting Gravatar...
Thanks for sharing..helped me a lot.
Left by anjee on Dec 12, 2008 1:38 PM

# Help with EnumMemberAttribute? | keyongtech

Requesting Gravatar...
Help with EnumMemberAttribute? | keyongtech
Left by Pingback/TrackBack on Jan 18, 2009 11:24 AM

# re: C#: Enums and String Values

Requesting Gravatar...
Very good post, the best solution I found to this problem!
Left by Bira on Jan 23, 2009 11:56 AM

# re: C#: Enums and String Values

Requesting Gravatar...
very good
Left by a on Feb 11, 2009 7:27 AM

# re: C#: Enums and String Values

Requesting Gravatar...
cool
Left by terry on Apr 30, 2009 2:16 AM

# re: C#: Enums and String Values

Requesting Gravatar...
Why didn't you use Enum.GetValues instead of Enum.GetNames? Then you would have been able to avoid calling Enum.Parse later on.
Left by Tzadik on May 27, 2009 9:45 AM

# re: C#: Enums and String Values

Requesting Gravatar...
Extremely cool. Thanx. I implemented a custom enum sorting routine based on attributes.
Left by attribcoderfor theday on Sep 10, 2009 7:52 AM

# re: C#: Enums and String Values

Requesting Gravatar...
Thanks for your help but I have one question: how do you give the enumtype to the enumValueOf-method? I tried something like:

EnumUtils.enumValueOf("dossier",SubjectType);

(SubjectType is an enum made the way you described)

but this doesn't compile. I tried several things but didn't find it
Left by Joowa on Oct 26, 2009 1:53 PM

# re: C#: Enums and String Values

Requesting Gravatar...
I used this to implement enum based error codes. I got the benefit of enums and and associated 3 string attributes with each code. Thanks heaps for posting this fantastic tip!
Left by Peter on Nov 30, 2009 5:59 AM

# re: C#: Enums and String Values

Requesting Gravatar...
Good job, it will be usefull to many people to be able to have typed string constants.
Left by Kashif on Jan 28, 2010 1:36 PM

# re: C#: Enums and String Values

Requesting Gravatar...
Hi, thanks a lot this is great.

However, I am having a problem with the util function to return the enum object when passing a string.

For example, with your IceCream enum above:
IceCream test = EnumUtils.enumValueOf("Rocky Road", IceCream);

I get the following 3 errors with that statement:

The best overloaded method match for 'test1.EnumUtils.enumValueOf(string, System.Type)' has some invalid arguments

Argument '2': cannot convert from 'test1.IceCream' to 'System.Type'

'test1.IceCream' is a 'type' but is used like a 'variable'
Left by Steve on Feb 11, 2010 6:15 PM

# re: C#: Enums and String Values

Requesting Gravatar...
Here is the VB.NET version of the code, modified to handle EnumMemberAtributes instead of DescriptionAttributes. I enhanced it to handle when some of the enum members do not have the EnumMemberAttribute specified for them.

''' <summary>
''' Returns the Enum member that is labelled with the System.Runtime.Serialization.EnumMemberAttribute, if one is attached to the enum member containing the value specified in the Value parameter, otherwise try to return the enum member with the same name as the value parameter.
''' </summary>
<System.Runtime.CompilerServices.Extension()> _
Public Function getEnumValue(ByVal enumType As System.Type, ByVal value As String) As Object
Dim names As String() = System.Enum.GetNames(enumType)
For Each name As String In names
If (getString(DirectCast(System.Enum.Parse(enumType, name), System.Enum))).Equals(value) Then
Return System.Enum.Parse(enumType, name)
End If
Next name
Throw New ArgumentException("The string is not an EnumMember or name of an enum member of the specified enum.")
End Function

''' <summary>
''' Return the Value from the System.Runtime.Serialization.EnumMemberAttribute, if one is attached to the enum member, otherwise return the ToString() value of the enum member.
''' </summary>
<System.Runtime.CompilerServices.Extension()> _
Public Function getString(ByVal value As System.Enum) As Object
Dim fi As Reflection.FieldInfo = value.GetType().GetField(value.ToString())
Dim attributes As System.Runtime.Serialization.EnumMemberAttribute() = DirectCast(fi.GetCustomAttributes(GetType(System.Runtime.Serialization.EnumMemberAttribute), False), System.Runtime.Serialization.EnumMemberAttribute())
'If the attribute specified Custom Attribute type is not attached to the enum member, then an array with one empty struct is returned, and the value is null.
If (attributes.Length > 0 AndAlso attributes(0).Value IsNot Nothing) Then
Return attributes(0).Value
Else
Return value.ToString()
End If
End Function
Left by Ananda on Feb 11, 2010 7:59 PM

# re: C#: Enums and String Values

Requesting Gravatar...
Thanks for the help, I was missing the cast to Enum in the equality check...

Here's my code using generics w/ C#:

/// <summary>
/// Helper class for <see cref="Enum"/>s.
/// </summary>
public static class EnumHelper
{
/// <summary>
/// Parses the specified value.
/// </summary>
/// <typeparam name="T">Base Type Enum</typeparam>
/// <param name="value">The value.</param>
/// <returns>The enum value matching the value provided.</returns>
public static T Parse<T>(string value)
{
return (T)Enum.Parse(typeof(T), value);
}

/// <summary>
/// Parses the specified description value.
/// </summary>
/// <typeparam name="T">Base Type Enum</typeparam>
/// <param name="value">The value.</param>
/// <returns>The enum value matching the decription provided; otherwise the first item in your enum if not found.</returns>
public static T ParseByDescription<T>(string value)
{
foreach (var name in Enum.GetNames(typeof(T)))
{
var enumValue = Parse<T>(name) as Enum;
if (enumValue.Description().Equals(value))
{
return Parse<T>(name);
}
}

return default(T);
}

/// <summary>
/// Returns the text value of the DescriptionAttribute for the given enum.
/// If no description attribute is found, the enum's .ToString() value is returned.
/// </summary>
/// <param name="enumeration">The enumeration.</param>
/// <returns>The value from the <see cref="DescriptionAttribute"/>. If not available then performs a ToString().</returns>
public static string Description(this Enum enumeration)
{
var value = enumeration.ToString();
var type = enumeration.GetType();
var descAttribute = (DescriptionAttribute[])type.GetField(value).GetCustomAttributes(typeof(DescriptionAttribute), false);
return descAttribute.Length > 0 ? descAttribute[0].Description : value;
}
}

Usage:
var myValue = EnumHelper.ParseByDescription<IceCream>("Rocky Road");
Left by Werewolf on Apr 01, 2010 2:27 PM

# re: C#: Enums and String Values

Requesting Gravatar...
great dude. mast code aahe. Jay maharashtra
Left by satish on Jun 25, 2010 2:59 AM

# re: C#: Enums and String Values

Requesting Gravatar...
Great post! I didn't really like how c# does it ,java wins in this area.
Left by someone on Jul 01, 2010 4:02 AM

# re: C#: Enums and String Values

Requesting Gravatar...
Unless I'm missing something, I don't think I agree with this approach. I think the reason Strings weren't included in enums for the Framework is because you wouldn't be able to use the [Flags] attribute. (You can't do bitwise operations on 'ChocolateChips' and 'Rocky Road'.

Enums are really just type-safe constants. If you really want strings, I would consider something like the following instead:


public class IceCream
{
public const string ChocolateChip = "Chocolate Chip";
public const string RockyRoad = "Rocky Road";
public const string Vanilla = "Vanilla";
}


You'll get intellisense and a level of safety by limiting your values to the values you put in the IceCream class.
Left by Waver on Oct 18, 2010 3:15 PM

# re: C#: Enums and String Values

Requesting Gravatar...
I disagree. Bitwise operations certainly can be applied. The whole point is that a String parameter can contain anything, whereas an enumeration constrains the domain of acceptable values.
Left by Wayne on Oct 18, 2010 3:41 PM

# re: C#: Enums and String Values

Requesting Gravatar...
Sorry. I guess I am missing something. I'm talking about using bitwise operations with the FlagsAttribute. For example,


[Flags]
public enum IceCream
{
ChocolateChip = 0,
RockyRoad = 1,
Vanilla = 2,
Strawberry = 4,
CherryGarcia = 8
}

IceCream iceCream = IceCream.RockyRoad | IceCream.CherryGarcia;


As you know, in this manner, I can indicate that my favorite Ice Cream is RockyRoad and CherryGarcia.

I don't see how I could do the same bitwise operations using strings. For example, the framework doesn't allow the following and would never work in the same manner:


[Flags]
public enum IceCream
{
ChocolateChip = "Chocolate Chip",
RockyRoad = "Rocky Road",
Vanilla = "Vanilla",
CherryGarcia = "Cherry Garcia"
}


Similarly, you could do bitwise operation on simple ints:


int a = 1;
int b = 8;
int c = a | b;
Console.WriteLine(c);


But you can't do that with strings:


string e = "Rocky Road";
string f = "Cherry Garcia";

string g = e | f; // ???
Console.WriteLine(g);


If the framework allowed the following, you'd be correct, and could perform bitwise operations:


[Flags]
public enum IceCream
{
"Chocolate Chip" = 0,
"Rocky Road" = 1,
"Vanilla" = 2,
"Strawberry" = 4,
"Cherry Garcia" = 8
}


However, you stated the "utter lack of string VALUE enumerations."


I somehow feel we might be in agreement if we were speaking in person, and I'm just missing what you're trying to communicate in writing. And I certainly agree with your usage of the 'DescriptionAttribute'. I've used it quite often. But because of the 'DescriptionAttribute', I've just never found the lack of string VALUE enumerations to be an issue and I just always assumed they kept enums numerical for bitwise operations.

Perhaps what I'm missing is just an issue of symantics?

Left by Waver on Oct 19, 2010 7:26 AM

# re: C#: Enums and String Values

Left by Ben on Mar 14, 2011 4:47 PM

# re: C#: Enums and String Values

Requesting Gravatar...
Thanks a lot... the article is very helpful in my case...

For those who were unable to use 'enumvalyeOf', try below,

// Get the enum value of the string
object xx = EnumUtils.enumValueOf(type, typeof(YourEnumName));
Left by MKar on Dec 16, 2011 9:00 AM

Your comment:

 (will show your gravatar)
 
Please add 4 and 6 and type the answer here: