Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to strictly parse string to enum?

Tags:

c#

enums

Let's say I have an enum:

public enum MyEnum
{
    OptionOne = 0,
    OptionTwo = 2,
    OptionThree = 4
}

Like it was said in the How should I convert a string to an enum in C#? question, I parse enum from string, using Enum.Parse method:

public class Enumer
{
    public static MyEnum? ParseEnum(string input)
    {
        try
        {
            return (MyEnum) Enum.Parse(typeof (MyEnum), input);
        }
        catch (ArgumentException)
        {
            return null;
        }
    }

}

Unfortunately, it doesn't work as expected with integer numbers, represented as strings.
I do not expect Parse.Enum() to convert int from string, but actually it does.
A simple test:

[TestClass]
public class Tester
{
    [TestMethod]
    public void TestEnum()
    {
        Assert.AreEqual(MyEnum.OptionTwo, Enumer.ParseEnum("OptionTwo"));
        Assert.IsNull(Enumer.ParseEnum("WrongString"));
        Assert.IsNull(Enumer.ParseEnum("2")); // returns 2 instead of null
        Assert.IsNull(Enumer.ParseEnum("12345")); // returns 12345 instead of null
    }
}

Only two checks of four can be passed.
Enumer.ParseEnum("2") returns MyEnum.OptionTwo instead of null.
Moreover, Enumer.ParseEnum("12345") returns 12345, regardless it's out of the scope.

What is the best way to parse:

  1. Only string values of "MyEnum.OptionOne", "MyEnum.OptionTwo", "MyEnum.OptionThree" into their enum counterparts.
  2. Strings "MyEnum.OptionOne", "MyEnum.OptionTwo", "MyEnum.OptionThree" AND the values of 0, 2 and 4 into MyEnum.OptionOne, MyEnum.OptionTwo, MyEnum.OptionThree respectively?

The link to the similar question How should I convert a string to an enum in C#? doesn't help with the test provided - it still converts strings as integers, even when they are out of the enum scope.

like image 266
enkryptor Avatar asked Apr 11 '16 15:04

enkryptor


1 Answers

You can do this yourself using Enum.GetValues(Type enumType).

public static MyEnum? ParseEnum(string input)
{
    return (MyEnum?) Enum.GetValues(typeof(MyEnum)).OfType<object>()
                         .FirstOrDefault(v => v.ToString() == input);
}

Adding support for integers you can also add.

public static MyEnum? ParseEnum(string input)
{
    int value;
    var isInt = int.TryParse(input, out value);
    return (MyEnum?) Enum.GetValues(typeof(MyEnum)).OfType<object>()
                         .FirstOrDefault(v => v.ToString() == input
                                           || (isInt & (int)v == value));
}

Since I am not 100% sure about your last requirements I add one that includes the name as well and is more generic

public static T? ParseEnum<T>(string input)
    where T : struct 
{
    int value;
    var isInt = int.TryParse(input, out value);
    return (T?)Enum.GetValues(typeof(T)).OfType<object>()
                   .FirstOrDefault(v => v.ToString() == typeof(T).Name + input
                                    || (isInt & (int)v == value));
}
like image 74
Toxantron Avatar answered Nov 15 '22 07:11

Toxantron