Comment convertir une chaîne en enum en C#?

Quelle est la meilleure façon de convertir une chaîne de caractères en valeur d'énumération en C#?

j'ai une balise HTML select contenant les valeurs d'une énumération. Quand la page est postée, je veux prendre la valeur (qui sera sous la forme d'une chaîne de caractères) et la convertir à la valeur d'énumération.

dans un monde idéal, je pourrais faire quelque chose comme ça:

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

mais ce n'est pas un code valide.

579
demandé sur Kirill Kobelev 2008-08-19 16:51:55

20 réponses

.NET de Base et .NET >4 il y a un générique de la méthode d'analyse :

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

Cela inclut également la nouvelle inline de C#7 out variables, donc cela fait l'essai-parse, la conversion au type enum explicite et initialise+popule la variable myStatus .

si vous avez accès à C#7 et le dernier .NET c'est la meilleure façon.

Réponse Originale À Cette Question

In .NET c'est plutôt moche (jusqu'à 4 ou ci-dessus):

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

j'ai tendance à simplifier avec:

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

je peux le faire:

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

une option suggérée dans les commentaires est d'ajouter une extension, ce qui est assez simple:

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

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

enfin, vous pouvez avoir un enum par défaut à utiliser si la chaîne ne peut pas être analysée:

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

ce qui fait de celui-ci appel:

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

cependant, je serais prudent d'ajouter une méthode d'extension comme celle-ci à string car (sans contrôle de l'Espace-nom) elle apparaîtra sur toutes les instances de string qu'elles contiennent ou non un enum (donc 1234.ToString().ToEnum(StatusEnum.None) serait valide mais non logique) . Il est souvent préférable d'éviter D'encombrer les classes de base de Microsoft avec des méthodes supplémentaires qui ne s'appliquent que dans des contextes très spécifiques à moins que toute votre équipe de développement a une très bonne compréhension de ce que ces extensions le font.

979
répondu Keith 2017-02-16 16:58:04

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

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

il peut être encore simplifié avec C# 7.0 type de paramètre inlining :

Enum.TryParse("Active", out StatusEnum myStatus);
246
répondu Erwin Mayer 2017-10-14 16:20:56

Note que la performance de l'Enum.Parse () est terrible, parce qu'il est mis en œuvre via la réflexion. (Il en va de même pour Enum.ToString, qui va dans l'autre sens.)

si vous avez besoin de convertir des chaînes en Enums en code sensible aux performances, votre meilleure chance est de créer un Dictionary<String,YourEnum> au démarrage et de l'utiliser pour faire vos conversions.

163
répondu McKenzieG1 2008-09-02 02:27:07

vous cherchez Enum.Parse .

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
70
répondu DavidWhitney 2015-08-30 12:37:12

vous pouvez utiliser méthodes d'extension maintenant:

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

et vous pouvez les appeler par le code ci-dessous (ici, FilterType est un type enum):

FilterType filterType = type.ToEnum<FilterType>();
23
répondu Foyzul Karim 2015-08-30 12:40:29
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

donc si vous aviez un énum nommé mood il ressemblerait à ceci:

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());
15
répondu brendan 2008-08-19 12:58:57

attention:

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

Enum.(Try)Parse() accepte plusieurs arguments séparés par des virgules, et les combine avec des arguments binaires 'ou' | . Vous ne pouvez pas désactiver cette et à mon avis vous presque jamais le souhaitez.

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

même si Three n'était pas défini, x obtiendrait quand même la valeur int 3 . C'est encore pire: Enum.Parse() peut vous donner une valeur qui n'est pas même défini pour l'enum!

Je ne voudrais pas faire l'expérience des conséquences des utilisateurs, volontairement ou non, déclenchant ce comportement.

en outre, comme mentionné par d'autres, la performance est moins qu'idéal pour les grands énums, à savoir linéaire dans le nombre de valeurs possibles.

je suggère ce qui suit:

    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
répondu Timo 2016-03-22 08:21:54

Enum.Analyser est votre ami:

StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
12
répondu tags2k 2015-08-30 12:37:32

vous pouvez étendre la réponse acceptée avec une valeur par défaut pour éviter les 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;
    }
}

alors vous l'appelez comme:

StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
12
répondu Nelly 2015-08-30 12:42:52

nous ne pouvions pas supposer une entrée parfaitement valide, et sommes allés avec cette variation de la réponse de @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
répondu gap 2012-08-30 15:07:10
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}
7
répondu Mark Cidade 2014-09-05 15:06:47

Analyse de la chaîne de TEnum sans try/catch et sans TryParse() la méthode de .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
répondu jite.gs 2013-10-30 12:46:11

essayez cet échantillon:

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

dans cet exemple, vous pouvez envoyer chaque chaîne, et définir votre Enum . Si votre Enum avait des données que vous vouliez, retournez-les comme votre type Enum .

GoodLock.

4
répondu AmirReza-Farahlagha 2018-10-01 15:28:38

Super simple code à l'aide de TryParse:

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;
3
répondu Brian Rice 2016-11-25 02:30:35

j'aime la solution de la méthode d'extension..

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

ci-dessous mon implémentation avec des 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
        }
2
répondu alhpe 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

====================Un Programme Complet====================

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
répondu Rae Lee 2015-08-18 05:28:07

j'ai utilisé la classe (fortement typées version de Enum avec l'analyse et des améliorations de performances). Je l'ai trouvé sur GitHub, et ça devrait marcher pour .NET 3.5 aussi. Il a un peu de mémoire au-dessus de lui car il tamponne un dictionnaire.

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

Le blog est Enums – Meilleure syntaxe, l'amélioration de la performance et de TryParse NET 3.5 .

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

1
répondu Patrik Lindström 2015-08-30 16:33:43

Pour la performance, ce qui pourrait aider:

    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
répondu Koray 2016-06-22 14:10:58

j'ai trouvé que le cas avec les valeurs enum qui ont la valeur EnumMember N'a pas été considéré. Nous y voilà:

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

et exemple de cet enum:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}
1
répondu isxaker 2016-10-04 16:40:31

vous devez utiliser Enum.Parse pour obtenir la valeur de l'objet à partir D'Enum, après cela vous devez changer la valeur de l'objet en valeur d'enum spécifique. Casting to enum valeur peut être fait en utilisant Convert.ChangeType. S'il vous plaît jeter un oeil sur l'extrait de code suivant

public T ConvertStringValueToEnum<T>(string valueToParse){
    return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}
1
répondu Bartosz Gawron 2017-02-12 12:11:01