Преобразовать строку в перечисление в C # - PullRequest
705 голосов
/ 19 августа 2008

Как лучше всего преобразовать строку в значение перечисления в C #?

У меня есть HTML-тег выбора, содержащий значения перечисления. Когда страница будет опубликована, я хочу выбрать значение (которое будет в форме строки) и преобразовать его в значение перечисления.

В идеальном мире я мог бы сделать что-то вроде этого:

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

но это неверный код.

Ответы [ 22 ]

1201 голосов
/ 19 августа 2008

В .NET Core и .NET> 4 есть общий метод синтаксического анализа :

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

Сюда также входят новые встроенные переменные out в C # 7, так что при этом выполняется попытка синтаксического анализа, преобразование в явный тип enum и инициализация + заполнения переменной myStatus.

Если у вас есть доступ к C # 7 и последней версии .NET, это лучший способ.

Оригинальный ответ

В .NET это довольно некрасиво (до 4 или выше):

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

Я склонен упростить это с помощью:

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

Тогда я могу сделать:

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

В комментариях предлагается один вариант - добавить расширение, которое достаточно просто:

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

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

Наконец, вы можете захотеть использовать перечисление по умолчанию, если строка не может быть проанализирована:

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;
}

Что делает этот звонок:

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

Однако я бы осторожно добавил такой метод расширения к string, поскольку (без управления пространством имен) он будет отображаться во всех экземплярах string независимо от того, содержат ли они перечисление или нет (поэтому 1234.ToString().ToEnum(StatusEnum.None) будет допустимым но бессмысленно). Часто лучше избегать загромождения основных классов Microsoft дополнительными методами, которые применяются только в очень специфических контекстах, если ваша команда разработчиков не очень хорошо понимает, что делают эти расширения.

283 голосов
/ 05 декабря 2013

Использование Enum.TryParse<T>(String, T) (≥ .NET 4.0):

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

Это может быть еще более упрощено с помощью встроенного типа параметра C # 7.0 :

Enum.TryParse("Active", out StatusEnum myStatus);
175 голосов
/ 02 сентября 2008

Обратите внимание, что производительность Enum.Parse () ужасна, потому что она реализована с помощью отражения. (То же самое относится и к Enum.ToString, который идет другим путем.)

Если вам нужно преобразовать строки в Enums в чувствительном к производительности коде, лучше всего при запуске создать Dictionary<String,YourEnum> и использовать его для конвертации.

82 голосов
/ 19 августа 2008

Вы ищете Enum.Parse .

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
26 голосов
/ 10 февраля 2014

Вы можете использовать методы расширения сейчас:

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

И вы можете вызвать их по следующему коду (здесь FilterType - это тип enum):

FilterType filterType = type.ToEnum<FilterType>();
16 голосов
/ 14 декабря 2015

BEWARE:

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

Enum.(Try)Parse() принимает несколько аргументов, разделенных запятыми, и объединяет их с двоичными значениями 'или' |. Вы не можете отключить это, и, по моему мнению, вы почти никогда не хотите этого.

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

Даже если Three не был определен, x все равно получит значение int 3. Это еще хуже: Enum.Parse () может дать вам значение, которое даже не определено для перечисления!

Я бы не хотел, чтобы пользователи, добровольно или невольно, испытывали последствия, вызывающие такое поведение.

Кроме того, как уже упоминалось другими, производительность не идеальна для больших перечислений, а именно линейна по числу возможных значений.

Я предлагаю следующее:

    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);
    }
16 голосов
/ 19 августа 2008
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

Так что, если бы у вас был enum по имени настроение, это выглядело бы так:

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());
15 голосов
/ 19 августа 2008

Enum.Parse ваш друг:

StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
12 голосов
/ 09 декабря 2014

Вы можете расширить принятый ответ значением по умолчанию, чтобы избежать исключений:

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;
    }
}

Тогда вы называете это как:

StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
9 голосов
/ 30 августа 2012

Мы не могли предположить, что ввод действителен, и согласились с этим вариантом ответа @ Keith:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...