Jak przekonwertować string na enum w C#?

Jaki jest najlepszy sposób na konwersję ciągu znaków na wartość wyliczenia w C#?

Mam znacznik HTML select zawierający wartości z wyliczenia. Kiedy strona jest publikowana, chcę podnieść wartość (która będzie w postaci łańcucha znaków) i przekonwertować ją na wartość wyliczenia.

W idealnym świecie mógłbym zrobić coś takiego:

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

Ale to nie jest prawidłowy kod.

Author: Kirill Kobelev, 2008-08-19

20 answers

W. NET Core i. Net >4 istnieje ogólna metoda parsowania :

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

Obejmuje to również nowe zmienne inline out W C#7, więc wykonuje to try-parse, konwersję do jawnego typu enum i inicjalizuje+wypełniając zmienną myStatus.

Jeśli masz dostęp do C # 7 i najnowszego. NET to jest najlepszy sposób.

Oryginalna Odpowiedź

W. NET jest raczej brzydko (do 4 lub wyżej):

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

Staram się uprościć to z:

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

Wtedy mogę zrobić:

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

Jedną z opcji sugerowanych w komentarzach jest dodanie rozszerzenia, co jest dość proste:

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

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

Wreszcie, możesz chcieć użyć domyślnego enum, jeśli łańcuch nie może być parsowany:

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

Co sprawia, że jest to wezwanie:

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

Jednakże, byłbym ostrożny dodając metodę rozszerzenia, taką jak ta do string, ponieważ (bez kontroli przestrzeni nazw) będzie ona wyświetlana na wszystkich instancjach string niezależnie od tego, czy posiadają enum, czy nie (więc 1234.ToString().ToEnum(StatusEnum.None) byłoby ważne, ale bezsensowne) . Często najlepiej jest unikać zaśmiecania podstawowych klas Microsoftu dodatkowymi metodami, które mają zastosowanie tylko w bardzo specyficznych kontekstach, chyba że cały zespół programistów ma bardzo dobre zrozumienie tego, co robią te rozszerzenia.

 979
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-16 16:58:04

Użycie Enum.TryParse<T>(String, T) (≥ . NET 4.0):

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

Może być jeszcze bardziej uproszczone z C# 7.0 ' s typ parametru inlining :

Enum.TryParse("Active", out StatusEnum myStatus);
 246
Author: Erwin Mayer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-14 16:20:56

Zwróć uwagę, że wydajność Enum.Parse() jest okropne, ponieważ jest zaimplementowane poprzez reflection. (To samo dotyczy Enum.ToString, który idzie w drugą stronę.)

Jeśli chcesz przekonwertować ciągi znaków na liczby w kodzie wrażliwym na wydajność, najlepiej utworzyć Dictionary<String,YourEnum> przy starcie i użyć go do konwersji.

 163
Author: McKenzieG1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-02 02:27:07

Szukasz Enum.Parse .

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
 70
Author: DavidWhitney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-30 12:37:12

Możesz użyć metody rozszerzenia Teraz:

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

I możesz je wywołać za pomocą poniższego kodu (tutaj FilterType jest typem enum):

FilterType filterType = type.ToEnum<FilterType>();
 23
Author: Foyzul Karim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-30 12:40:29
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

Więc gdybyś miał enum o nazwie mood to wyglądałoby to tak:

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());
 15
Author: brendan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 12:58:57

Uwaga:

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

Enum.(Try)Parse() przyjmuje wiele argumentów oddzielonych przecinkami i łączy je z binarnym 'lub' |. Nie możesz tego wyłączyć i moim zdaniem prawie nigdy tego nie chcesz.

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

Nawet jeśli Three nie został zdefiniowany, x nadal otrzymałby wartość int 3. To jeszcze gorzej: Enum.Parse() może dać wartość, która nie jest nawet zdefiniowana dla enum!

Nie chciałbym doświadczać konsekwencji użytkowników, chętnie lub niechętnie, wywołanie takiego zachowania.

Dodatkowo, jak wspomniano przez innych, wydajność jest mniejsza niż idealna dla dużych enum, a mianowicie liniowa w liczbie możliwych wartości.

Proponuję:

    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);
    }
 14
Author: Timo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-22 08:21:54

Enum.Parse jest twoim przyjacielem:

StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
 12
Author: tags2k,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-30 12:37:32

Możesz rozszerzyć akceptowaną odpowiedź o wartość domyślną, aby uniknąć WYJĄTKÓW:

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

Wtedy nazywacie to tak:

StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
 12
Author: Nelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-30 12:42:52

Nie mogliśmy założyć idealnie poprawnego wejścia, i poszliśmy z tą odmianą odpowiedzi @ 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;
}
 9
Author: gap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-30 15:07:10
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}
 7
Author: Mark Cidade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-05 15:06:47

Parsuje string do TEnum bez metody try/catch i bez metody TryParse () z. 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;
}
 5
Author: jite.gs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-30 12:46:11

Spróbuj tej próbki:

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

W tej próbce możesz wysłać każdy ciąg i ustawić Enum. Jeśli twój Enum miał dane, które chciałeś, zwróć je jako swój typ Enum.

GoodLock.
 4
Author: AmirReza-Farahlagha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-01 15:28:38

Super prosty kod za pomocą TryParse:

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;
 3
Author: Brian Rice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-25 02:30:35

Podoba mi się rozwiązanie metody rozszerzenia..

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

Poniżej moja implementacja z testami.

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
        }
 2
Author: alhpe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-01 21:57:29
public static T ParseEnum<T>(string value)            //function declaration  
{
    return (T) Enum.Parse(typeof(T), value);
}

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

====================Kompletny 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.
 1
Author: Rae Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-18 05:28:07

Użyłem class (mocno wpisanej wersji Enum z parsowaniem i ulepszeniami wydajności). Znalazłem go na Githubie i powinien działać również dla. NET 3.5. Ma trochę pamięci, ponieważ buforuje słownik.

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

Blogpost jest Enums-lepsza składnia, lepsza wydajność i Tryparowanie w sieci 3.5.

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

 1
Author: Patrik Lindström,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-30 16:33:43

Dla wydajności może to pomóc:

    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];
    }
 1
Author: Koray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-22 14:10:58

Odkryłem, że tutaj przypadek z wartościami enum, które mają wartość EnumMember nie został uwzględniony. No to zaczynamy:

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

I przykład tego enum:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}
 1
Author: isxaker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-04 16:40:31

Musisz użyć Enum.Parse, aby uzyskać wartość obiektu z Enum, następnie musisz zmienić wartość obiektu na określoną wartość enum. Odlewanie do wartości enum można wykonać za pomocą konwersji.Typ zmiany. Proszę spojrzeć na poniższy fragment kodu

public T ConvertStringValueToEnum<T>(string valueToParse){
    return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}
 1
Author: Bartosz Gawron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-12 12:11:01