Вопрос:

Преобразовать строку в перечисление в C #

c# string enums

539966 просмотра

22 ответа

10519 Репутация автора

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

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

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

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

но это не правильный код

Автор: Ben Mills Источник Размещён: 19.08.2008 12:51

Ответы (22)


82 плюса

3165 Репутация автора

Вы ищете Enum.Parse .

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
Автор: DavidWhitney Размещён: 19.08.2008 12:53

1191 плюса

96395 Репутация автора

Решение

В .NET Core и .NET> 4 есть универсальный метод разбора :

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

Это также включает в себя новые встроенные outпеременные C # 7 , так что это делает try-parse, преобразование в явный тип 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 дополнительными методами, которые применяются только в очень специфических контекстах, если ваша команда разработчиков не очень хорошо понимает, что делают эти расширения.

Автор: Keith Размещён: 19.08.2008 12:54

15 плюса

29587 Репутация автора

Enum.Parse твой друг:

StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
Автор: tags2k Размещён: 19.08.2008 12:55

16 плюса

22337 Репутация автора

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

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

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());
Автор: brendan Размещён: 19.08.2008 12:58

7 плюса

85862 Репутация автора

// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}
Автор: Mark Cidade Размещён: 19.08.2008 01:13

174 плюса

9711 Репутация автора

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

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

Автор: McKenzieG1 Размещён: 02.09.2008 02:27

9 плюса

1779 Репутация автора

Мы не могли предположить совершенно достоверный ввод и пошли с этим вариантом ответа @ 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;
}
Автор: gap Размещён: 30.08.2012 03:07

5 плюса

51 Репутация автора

Разбирает строку в TEnum без try / catch и без метода TryParse () из .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;
}
Автор: jite.gs Размещён: 17.10.2013 04:04

282 плюса

10949 Репутация автора

Используйте Enum.TryParse<T>(String, T)(≥ .NET 4.0):

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

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

Enum.TryParse("Active", out StatusEnum myStatus);
Автор: Erwin Mayer Размещён: 05.12.2013 08:22

26 плюса

2389 Репутация автора

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

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>();
Автор: Foyzul Karim Размещён: 10.02.2014 10:12

12 плюса

434 Репутация автора

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

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);
Автор: Nelly Размещён: 09.12.2014 11:43

1 плюс

740 Репутация автора

Я использовал класс (строго типизированная версия Enum с разбором и улучшением производительности). Я нашел его на GitHub, и он должен работать и для .NET 3.5. Он имеет некоторые накладные расходы памяти, поскольку он буферизует словарь.

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

Блог пост Enums - лучший синтаксис, улучшенная производительность и TryParse в NET 3.5 .

И код: https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs

Автор: Patrik Lindström Размещён: 01.07.2015 09:39

1 плюс

741 Репутация автора

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

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

==================== Полная программа ====================

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.
Автор: Rae Lee Размещён: 18.08.2015 05:28

2 плюса

574 Репутация автора

Мне нравится решение метода расширения ..

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

Здесь ниже моя реализация с тестами.

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
        }
Автор: alhpe Размещён: 01.10.2015 09:57

16 плюса

3403 Репутация автора

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 () может дать вам значение, которое даже не определено для enum!

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

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

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

    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);
    }
Автор: Timo Размещён: 14.12.2015 12:31

1 плюс

841 Репутация автора

Для производительности это может помочь:

    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];
    }
Автор: Koray Размещён: 22.06.2016 02:10

1 плюс

3427 Репутация автора

Я обнаружил, что здесь случай со значениями перечисления, которые имеют значение EnumMember, не рассматривался. Итак, поехали:

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

И пример этого перечисления:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}
Автор: isxaker Размещён: 04.10.2016 04:40

3 плюса

1274 Репутация автора

Супер простой код с использованием TryParse:

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;
Автор: Brian Rice Размещён: 25.11.2016 02:30

1 плюс

81 Репутация автора

Вы должны использовать Enum.Parse, чтобы получить значение объекта из Enum, после этого вы должны изменить значение объекта на конкретное значение перечисления. Приведение к перечисляемому значению можно выполнить с помощью Convert.ChangeType. Пожалуйста, взгляните на следующий фрагмент кода

public T ConvertStringValueToEnum<T>(string valueToParse){
    return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}
Автор: Bartosz Gawron Размещён: 08.02.2017 11:33

1 плюс

644 Репутация автора

Попробуйте этот образец:

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

В этом примере вы можете отправить каждую строку и установить свой Enum. Если у вас Enumесть данные, которые вы хотели, верните их как ваш Enumтип.

Автор: AmirReza-Farahlagha Размещён: 01.10.2018 09:37

0 плюса

300 Репутация автора

        <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
Автор: AHMED RABEE Размещён: 22.05.2019 07:15

0 плюса

300 Репутация автора

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

return Enum.Parse(typeof(TEnum), value, true);}
Автор: AHMED RABEE Размещён: 22.05.2019 07:19
32x32