What's the best way to convert a string to an enumeration value in C#?

I have an HTML select tag containing the values of an enumeration. When the page is posted, I want to pick up the value (which will be in the form of a string) and convert it to the corresponding enumeration value.

In an ideal world, I could do something like this:

StatusEnum MyStatus = StatusEnum.Parse("Active");

but that isn't a valid code.

Solution 1

In .NET Core and .NET Framework 4.0 there is a generic parse method:

Enum.TryParse("Active", out StatusEnum myStatus);

This also includes C#7's new inline out variables, so this does the try-parse, conversion to the explicit enum type and initialises+populates the myStatus variable.

If you have access to C#7 and the latest .NET this is the best way.

Original Answer

In .NET it's rather ugly (until 4 or above):

StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);

I tend to simplify this with:

public static T ParseEnum<T>(string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

Then I can do:

StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");

One option suggested in the comments is to add an extension, which is simple enough:

public static T ToEnum<T>(this string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();

Finally, you may want to have a default enum to use if the string cannot be parsed:

public static T ToEnum<T>(this string value, T defaultValue) 
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    T result;
    return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

Which makes this the call:

StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);

However, I would be careful adding an extension method like this to string as (without namespace control) it will appear on all instances of string whether they hold an enum or not (so 1234.ToString().ToEnum(StatusEnum.None) would be valid but nonsensical) . It's often be best to avoid cluttering Microsoft's core classes with extra methods that only apply in very specific contexts unless your entire development team has a very good understanding of what those extensions do.

Solution 2

Use Enum.TryParse<T>(String, T) ( .NET 4.0):

StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);

It can be simplified even further with C# 7.0's parameter type inlining:

Enum.TryParse("Active", out StatusEnum myStatus);

Solution 3

Note that the performance of Enum.Parse() is awful, because it is implemented via reflection. (The same is true of Enum.ToString, which goes the other way.)

If you need to convert strings to Enums in performance-sensitive code, your best bet is to create a Dictionary<String,YourEnum> at startup and use that to do your conversions.

Solution 4

You're looking for Enum.Parse.

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");

Solution 5

You can use extension methods now:

public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
    return (T) Enum.Parse(typeof (T), value, ignoreCase);
}

And you can call them by the below code (here, FilterType is an enum type):

FilterType filterType = type.ToEnum<FilterType>();

Solution 6

BEWARE:

enum Example
{
    One = 1,
    Two = 2,
    Three = 3
}

Enum.(Try)Parse() accepts multiple, comma-separated arguments, and combines them with binary 'or' |. You cannot disable this and in my opinion you almost never want it.

var x = Enum.Parse("One,Two"); // x is now Three

Even if Three was not defined, x would still get int value 3. That's even worse: Enum.Parse() can give you a value that is not even defined for the enum!

I would not want to experience the consequences of users, willingly or unwillingly, triggering this behavior.

Additionally, as mentioned by others, performance is less than ideal for large enums, namely linear in the number of possible values.

I suggest the following:

    public static bool TryParse<T>(string value, out T result)
        where T : struct
    {
        var cacheKey = "Enum_" + typeof(T).FullName;

        // [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
        // [Implementation off-topic.]
        var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);

        return enumDictionary.TryGetValue(value.Trim(), out result);
    }

    private static Dictionary<string, T> CreateEnumDictionary<T>()
    {
        return Enum.GetValues(typeof(T))
            .Cast<T>()
            .ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
    }

Solution 7

object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

So if you had an enum named mood it would look like this:

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());

Solution 8

Enum.Parse is your friend:

StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");

Solution 9

You can extend the accepted answer with a default value to avoid exceptions:

public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
    try
    {
        T enumValue;
        if (!Enum.TryParse(value, true, out enumValue))
        {
            return defaultValue;
        }
        return enumValue;
    }
    catch (Exception)
    {
        return defaultValue;
    }
}

Then you call it like:

StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);

If the default value is not an enum the Enum.TryParse would fail and throw an exception which is catched.

After years of using this function in our code on many places maybe it's good to add the information that this operation costs performance!

Solution 10

We couldn't assume perfectly valid input, and went with this variation of @Keith's answer:

public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
    TEnum tmp; 
    if (!Enum.TryParse<TEnum>(value, true, out tmp))
    {
        tmp = new TEnum();
    }
    return tmp;
}

Solution 11

At some point a generic version of Parse was added. For me this was preferable because I didn't need to "try" to parse and I also want the result inline without generating an output variable.

ColorEnum color = Enum.Parse<ColorEnum>("blue");

MS Documentation: Parse

Solution 12

// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}

Solution 13

Not sure when this was added but on the Enum class there is now a

Parse<TEnum>(stringValue)

Used like so with example in question:

var MyStatus = Enum.Parse<StatusEnum >("Active")

or ignoring casing by:

var MyStatus = Enum.Parse<StatusEnum >("active", true)

Here is the decompiled methods this uses:

    [NullableContext(0)]
    public static TEnum Parse<TEnum>([Nullable(1)] string value) where TEnum : struct
    {
      return Enum.Parse<TEnum>(value, false);
    }

    [NullableContext(0)]
    public static TEnum Parse<TEnum>([Nullable(1)] string value, bool ignoreCase) where TEnum : struct
    {
      TEnum result;
      Enum.TryParse<TEnum>(value, ignoreCase, true, out result);
      return result;
    }

Solution 14

Parses string to TEnum without try/catch and without TryParse() method from .NET 4.5

/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
    enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
    if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
        return false;

    enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
    return true;
}

Solution 15

Most of the answers here require you to always pass in the default value of the enum each time you call on the extension method. If you don't want to go by that approach, you can implement it like below:

 public static TEnum ToEnum<TEnum>(this string value) where TEnum : struct
 {
     if (string.IsNullOrWhiteSpace(value))
          return default(TEnum);

     return Enum.TryParse(value, true, out TEnum result) ? result : default(TEnum);

 }

Using default literal (available from C# 7.1)

 public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue = default) where TEnum : struct
 {
       if (string.IsNullOrWhiteSpace(value))
            return default;

       return Enum.TryParse(value, true, out TEnum result) ? result : default;

 }

Better still:

public static TEnum ToEnum<TEnum>(this string value) where TEnum : struct
{
      if (string.IsNullOrWhiteSpace(value))
           return default;

      return Enum.TryParse(value, true, out TEnum result) ? result : default;

}

Solution 16

I like the extension method solution..

namespace System
{
    public static class StringExtensions
    {

        public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
        {
            T result;

            var isEnum = Enum.TryParse(value, out result);

            output = isEnum ? result : default(T);

            return isEnum;
        }
    }
}

Here below my implementation with tests.

using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;

private enum Countries
    {
        NorthAmerica,
        Europe,
        Rusia,
        Brasil,
        China,
        Asia,
        Australia
    }

   [TestMethod]
        public void StringExtensions_On_TryParseAsEnum()
        {
            var countryName = "Rusia";

            Countries country;
            var isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsTrue(isCountry);
            AreEqual(Countries.Rusia, country);

            countryName = "Don't exist";

            isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsFalse(isCountry);
            AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
        }

Solution 17

Super simple code using TryParse:

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;

Solution 18

For performance this might help:

    private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
    public static T ToEnum<T>(this string value, T defaultValue)
    {
        var t = typeof(T);
        Dictionary<string, object> dic;
        if (!dicEnum.ContainsKey(t))
        {
            dic = new Dictionary<string, object>();
            dicEnum.Add(t, dic);
            foreach (var en in Enum.GetValues(t))
                dic.Add(en.ToString(), en);
        }
        else
            dic = dicEnum[t];
        if (!dic.ContainsKey(value))
            return defaultValue;
        else
            return (T)dic[value];
    }

Solution 19

If the property name is different from what you want to call it (i.e. language differences) you can do like this:

MyType.cs

using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

[JsonConverter(typeof(StringEnumConverter))]
public enum MyType
{
    [EnumMember(Value = "person")]
    Person,
    [EnumMember(Value = "annan_deltagare")]
    OtherPerson,
    [EnumMember(Value = "regel")]
    Rule,
}

EnumExtensions.cs

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

public static class EnumExtensions
{
    public static TEnum ToEnum<TEnum>(this string value) where TEnum : Enum
    {
        var jsonString = $"'{value.ToLower()}'";
        return JsonConvert.DeserializeObject<TEnum>(jsonString, new StringEnumConverter());
    }

    public static bool EqualsTo<TEnum>(this string strA, TEnum enumB) where TEnum : Enum
    {
        TEnum enumA;
        try
        {
            enumA = strA.ToEnum<TEnum>();
        }
        catch
        {
            return false;
        }
        return enumA.Equals(enumB);
    }
}

Program.cs

public class Program
{
    static public void Main(String[] args) 
    { 
        var myString = "annan_deltagare";
        var myType = myString.ToEnum<MyType>();
        var isEqual = myString.EqualsTo(MyType.OtherPerson);
        //Output: true
    }     
}

Solution 20

public static T ParseEnum<T>(string value)            //function declaration  
{
    return (T) Enum.Parse(typeof(T), value);
}

Importance imp = EnumUtil.ParseEnum<Importance>("Active");   //function call

====================A Complete Program====================

using System;

class Program
{
    enum PetType
    {
    None,
    Cat = 1,
    Dog = 2
    }

    static void Main()
    {

    // Possible user input:
    string value = "Dog";

    // Try to convert the string to an enum:
    PetType pet = (PetType)Enum.Parse(typeof(PetType), value);

    // See if the conversion succeeded:
    if (pet == PetType.Dog)
    {
        Console.WriteLine("Equals dog.");
    }
    }
}
-------------
Output

Equals dog.

Solution 21

I used class (strongly-typed version of Enum with parsing and performance improvements). I found it on GitHub, and it should work for .NET 3.5 too. It has some memory overhead since it buffers a dictionary.

StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");

The blogpost is Enums Better syntax, improved performance and TryParse in NET 3.5.

And code: https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs

Solution 22

I found that here the case with enum values that have EnumMember value was not considered. So here we go:

using System.Runtime.Serialization;

public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    TEnum result;
    var enumType = typeof(TEnum);
    foreach (var enumName in Enum.GetNames(enumType))
    {
        var fieldInfo = enumType.GetField(enumName);
        var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
        if (enumMemberAttribute?.Value == value)
        {
            return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
        }
    }

    return Enum.TryParse(value, true, out result) ? result : defaultValue;
}

And example of that enum:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}

Solution 23

You have to use Enum.Parse to get the object value from Enum, after that you have to change the object value to specific enum value. Casting to enum value can be do by using Convert.ChangeType. Please have a look on following code snippet

public T ConvertStringValueToEnum<T>(string valueToParse){
    return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}

Solution 24

Try this sample:

 public static T GetEnum<T>(string model)
    {
        var newModel = GetStringForEnum(model);

        if (!Enum.IsDefined(typeof(T), newModel))
        {
            return (T)Enum.Parse(typeof(T), "None", true);
        }

        return (T)Enum.Parse(typeof(T), newModel.Result, true);
    }

    private static Task<string> GetStringForEnum(string model)
    {
        return Task.Run(() =>
        {
            Regex rgx = new Regex("[^a-zA-Z0-9 -]");
            var nonAlphanumericData = rgx.Matches(model);
            if (nonAlphanumericData.Count < 1)
            {
                return model;
            }
            foreach (var item in nonAlphanumericData)
            {
                model = model.Replace((string)item, "");
            }
            return model;
        });
    }

In this sample you can send every string, and set your Enum. If your Enum had data that you wanted, return that as your Enum type.

Solution 25

public TEnum ToEnum<TEnum>(this string value, TEnum defaultValue){
if (string.IsNullOrEmpty(value))
    return defaultValue;

return Enum.Parse(typeof(TEnum), value, true);}

Solution 26

        <Extension()>
    Public Function ToEnum(Of TEnum)(ByVal value As String, ByVal defaultValue As TEnum) As TEnum
        If String.IsNullOrEmpty(value) Then
            Return defaultValue
        End If

        Return [Enum].Parse(GetType(TEnum), value, True)
    End Function

Solution 27

If you want to use a default value when null or empty (e.g. when retrieving from config file and the value does not exist) and throw an exception when the string or number does not match any of the enum values. Beware of caveat in Timo's answer though (https://stackoverflow.com/a/34267134/2454604).

    public static T ParseEnum<T>(this string s, T defaultValue, bool ignoreCase = false) 
        where T : struct, IComparable, IConvertible, IFormattable//If C# >=7.3: struct, System.Enum 
    {
        if ((s?.Length ?? 0) == 0)
        {
            return defaultValue;
        }

        var valid = Enum.TryParse<T>(s, ignoreCase, out T res);

        if (!valid || !Enum.IsDefined(typeof(T), res))
        {
            throw new InvalidOperationException(
                $"'{s}' is not a valid value of enum '{typeof(T).FullName}'!");
        }
        return res;
    }

Solution 28

I started to use this approach. Performance seems to be ok however it requires a bit of boilerplate code setup.

public enum StatusType {
    Success,
    Pending,
    Rejected
}

static class StatusTypeMethods {

    public static StatusType GetEnum(string type) {
        switch (type) {
            case nameof(StatusType.Success): return StatusType.Success;
            case nameof(StatusType.Pending): return StatusType.Pending;
            case nameof(StatusType.Rejected): return StatusType.Rejected;
            default:
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
        };
    }
}

And later on, you can use it like this:

StatusType = StatusType.GetEnum("Success");

Solution 29

First of all, you need to decorate your enum, like this:

    public enum Store : short
{
    [Description("Rio Big Store")]
    Rio = 1
}

in .net 5, i create this extension method:

//The class also needs to be static, ok?
public static string GetDescription(this System.Enum enumValue)
    {
        FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());

        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
            typeof(DescriptionAttribute), false);

        if (attributes != null && attributes.Length > 0) return attributes[0].Description;
        else return enumValue.ToString();
    }

now you have an extension methods to use in any Enums

Like this:

var Desc = Store.Rio.GetDescription(); //Store is your Enum