19

I have an enum type like this as an example:

public Enum MyEnum {
    enum1, enum2, enum3 };

I'll read a string from config file. What I need is to parse the string to MyEnum type or null or not defined. Not sure if the following code will work (sorry for not having access to my VS right now):

// example: ParseEnum<MyEnum>("ENUM1", ref eVal);
bool ParseEnum<T>(string value1, ref eVal) where T : Enum
{
  bool bRet = false;
  var x = from x in Enum.GetNames(typeof(T)) where 
       string.Equals(value1, x, StringComparison. OrdinalIgnoreCase)
       select x;
  if (x.Count() == 1 )
  {
    eVal = Enum.Parse(typeof(T), x.Item(0)) as T;
    bRet = true;
  }
  return bRet;
}

Not sure if it is correct or there is any other simple way to parse a string to a MyEnum value?

Pang
  • 9,564
  • 146
  • 81
  • 122
David.Chu.ca
  • 37,408
  • 63
  • 148
  • 190

8 Answers8

33

What about something like:

public static class EnumUtils
{
    public static Nullable<T> Parse<T>(string input) where T : struct
    {
        //since we cant do a generic type constraint
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("Generic Type 'T' must be an Enum");
        }
        if (!string.IsNullOrEmpty(input))
        {
            if (Enum.GetNames(typeof(T)).Any(
                  e => e.Trim().ToUpperInvariant() == input.Trim().ToUpperInvariant()))
            {
                return (T)Enum.Parse(typeof(T), input, true);
            }
        }
        return null;
    }
}

Used as:

MyEnum? value = EnumUtils.Parse<MyEnum>("foo");

(Note: old version used try/catch around Enum.Parse)

Rex M
  • 142,167
  • 33
  • 283
  • 313
5
private enum MyEnum
{
    Enum1 = 1, Enum2 = 2, Enum3 = 3, Enum4 = 4, Enum5 = 5, Enum6 = 6, 
    Enum7 = 7, Enum8 = 8, Enum9 = 9, Enum10 = 10
}

private static Object ParseEnum<T>(string s)
{
    try
    {
        var o = Enum.Parse(typeof (T), s);
        return (T)o;
    }
    catch(ArgumentException)
    {
        return null;
    }
}

static void Main(string[] args)
{
   Console.WriteLine(ParseEnum<MyEnum>("Enum11"));
   Console.WriteLine(ParseEnum<MyEnum>("Enum1"));
   Console.WriteLine(ParseEnum<MyEnum>("Enum6").GetType());
   Console.WriteLine(ParseEnum<MyEnum>("Enum10"));
}

OUTPUT:

    //This line is empty as Enum11 is not there and function returns a null
Enum1
TestApp.Program+MyEnum
Enum10
Press any key to continue . . .
TheVillageIdiot
  • 40,053
  • 20
  • 133
  • 188
4

This is an old question, but now .NET 4.5 has Enum.TryParse<TEnum>().

Pang
  • 9,564
  • 146
  • 81
  • 122
iheartcsharp
  • 1,279
  • 1
  • 14
  • 22
2

You can use TryParse if you want to avoid using try/catch.

MyEnum eVal;
if (Enum.TryParse("ENUM2", true, out eVal)){
    // now eVal is the enumeration element: enum2 
}
//unable to parse. You can log the error, exit, redirect, etc...

I modified the selected answer a little bit. I hope you like it.

public static class EnumUtils
{
    public static Nullable<T> Parse<T>(string input) where T : struct
    {
        //since we cant do a generic type constraint
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("Generic Type 'T' must be an Enum");
        }

        int intVal;
        if (!string.IsNullOrEmpty(input) && !int.TryParse(input, out intVal))
        {
            T eVal;
            if (Enum.TryParse(input, true, out eVal))
            {
                return eVal;
            }
        }
        return null;
    }
}
Jaider
  • 14,268
  • 5
  • 75
  • 82
2

If you're using .NET 3.5 (or even 2.0, if you trim out the extension method), I've had great luck with the techniques in this article:

Enumerations and Strings - Stop the Madness!

EDIT: Domain is gone and is now a link farm. I pulled the code (slightly modified and added to over time) from our codebase at work, which you can now find here:

https://gist.github.com/1305566

Chris Doggett
  • 19,959
  • 4
  • 61
  • 86
  • 2
    Reference now points to a link farm. I initially modded you down one, but you're pretty high-rep, so I'm guessing you're not doing this intentionally, and you shouldn't be penalized for what happens to content outside your control. I searched for the article myself but didn't turn anything obvious up. Can you see if there's a better link for this content? – Michael Blackburn Apr 12 '11 at 19:38
  • @MichaelBlackburn: Looks like the guy who had the domain disappeared. I'll check in our codebase on Monday and see if I can find what I borrowed from the article. – Chris Doggett Oct 22 '11 at 03:19
  • Yet another reason to paste the entire solution, instead of links. – Christian May 16 '19 at 12:10
2

I have a TryParseName method in UnconstrainedMelody, a library for delegate and enum utility methods which uses "inexpressible" constraints via some postbuild trickery. (Code using the library doesn't need a postbuild, just to be clear.)

You would use it like this:

Foo foo;
bool parsed = Enums.TryParseName<Foo>(name, out foo);

I don't currently have a case-insensitive version, but I could easily introduce one if you wanted. Note that this doesn't try to parse numbers e.g. "12" like the built-in version does, nor does it try to parse comma-separated lists of flags. I may add the flags version later on, but I can't see much point in the numeric version.

This is done without boxing and without execution time type checking. Having the constraint is really handy :)

Please let me know if you'd find a case-insensitive parse useful...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Jon Skeet, you may introduce additional overloaded method to let user to have choices of case-sensitive or not. – David.Chu.ca Sep 15 '09 at 13:08
  • @Joh Skeet, not sure if your method should be (name, ref foo) or not. If tryparse fails, what should foo be? The first enum value? I think is better to let user to initialize it and not change it if fails. I understand you try to make this method being consistent with TryParse(name, out value). – David.Chu.ca Sep 15 '09 at 13:14
  • 1
    If `TryParse` fails, it will be `default(Foo)` which is consistent with `TryParse`, `TryGetValue` etc. If I weren't going for consistency I'd probably return a `Nullable` instead. I'll look at introducing a new overload for case-insensitive matching - or possibly taking a StringComparer (or similar) to allow cultural sensitivity to be selected too. – Jon Skeet Sep 15 '09 at 13:21
2

I have just combined the syntax from here, with the exception handling from here, to create this:

public static class Enum<T>
{
    public static T Parse(string value)
    {
        //Null check
        if(value == null) throw new ArgumentNullException("value");
        //Empty string check
        value = value.Trim();
        if(value.Length == 0) throw new ArgumentException("Must specify valid information for parsing in the string", "value");
        //Not enum check
        Type t = typeof(T);
        if(!t.IsEnum) throw new ArgumentException("Type provided must be an Enum", "TEnum");

        return (T)Enum.Parse(typeof(T), value);
    }
}

You could twiddle it a bit to return null instead of throwing exceptions.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Benjol
  • 63,995
  • 54
  • 186
  • 268
0

To return Enum by string, if contains:

    public static T GetEnum<T>(string s)
    {
        Array arr = Enum.GetValues(typeof(T));
        foreach (var x in arr)
        {
            if (x.ToString().Contains(s))
                return (T)x;
        }
        return default(T);
    }
Rovann Linhalis
  • 601
  • 8
  • 14