Comment devrais-je convertir une chaîne en une énumération en C #?

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

J’ai une balise HTML select contenant les valeurs d’une énumération. Lorsque la page est publiée, je veux prendre la valeur (qui sera sous la forme d’une chaîne) et la convertir en valeur d’énumération.

Dans un monde idéal, je pourrais faire quelque chose comme ceci:

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

mais ce n’est pas un code valide.

Dans .NET Core et .NET> 4, il existe une méthode d’parsing générique :

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

Cela inclut également les nouvelles variables d’inline out C # 7, ce qui fait que try-parse, la conversion au type enum explicite et initialise + remplit la variable myStatus .

Si vous avez access à C # 7 et au dernier .NET, c’est le meilleur moyen.

Réponse originale

Dans .NET c’est plutôt moche (jusqu’à 4 ou plus):

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

J’ai tendance à simplifier cela avec:

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

Alors je peux faire:

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

Une option suggérée dans les commentaires consiste à append une extension, ce qui est assez simple:

 public static T ToEnum(this ssortingng value) { return (T) Enum.Parse(typeof(T), value, true); } StatusEnum MyStatus = "Active".ToEnum(); 

Enfin, vous voudrez peut-être utiliser un enum par défaut si la chaîne ne peut pas être analysée:

 public static T ToEnum(this ssortingng value, T defaultValue) { if (ssortingng.IsNullOrEmpty(value)) { return defaultValue; } T result; return Enum.TryParse(value, true, out result) ? result : defaultValue; } 

Ce qui en fait l’appel:

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

Cependant, je ferais attention en ajoutant une méthode d’extension comme celle-ci (sans contrôle d’espace de noms), elle apparaîtra sur toutes les instances de ssortingng qu’elles contiennent ou non une énumération (donc 1234.ToSsortingng().ToEnum(StatusEnum.None) être valide mais absurde). 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 votre équipe de développement ne comprenne parfaitement ce que font ces extensions.

Utilisez Enum.TryParse(Ssortingng, T) (≥ .NET 4.0):

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

Il peut être simplifié davantage avec le type de paramètre inline C : 7.0 :

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

Notez que les performances de Enum.Parse () sont terribles, car elles sont implémentées par reflection. (La même chose est vraie pour Enum.ToSsortingng, qui va dans l’autre sens.)

Si vous devez convertir des chaînes en Enums en code sensible aux performances, le mieux est de créer un Dictionary au démarrage et de l’utiliser pour effectuer vos conversions.

Vous cherchez Enum.Parse .

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

Vous pouvez utiliser les méthodes d’extension maintenant:

 public static T ToEnum(this ssortingng 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(); 
 object Enum.Parse(System.Type enumType, ssortingng value, bool ignoreCase); 

Donc, si vous aviez un enum nommé mood, ça ressemblerait à ceci:

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

IL FAUT SE MÉFIER:

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

Enum.(Try)Parse() accepte plusieurs arguments séparés par des virgules et les combine avec binary ‘ou’ | . Vous ne pouvez pas désactiver ceci et à mon avis vous ne le voulez presque jamais.

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

Même si Three n’était pas défini, x obtiendrait toujours int value 3 . C’est encore pire: Enum.Parse () peut vous donner une valeur qui n’est même pas définie pour l’énumération!

Je ne voudrais pas connaître les conséquences des utilisateurs, volontairement ou non, pour déclencher ce comportement.

De plus, comme mentionné par d’autres, la performance est loin d’être idéale pour les grandes énumérations, à savoir linéaire dans le nombre de valeurs possibles.

Je suggère ce qui suit:

  public static bool TryParse(ssortingng value, out T result) where T : struct { var cacheKey = "Enum_" + typeof(T).FullName; // [Use MemoryCache to resortingeve or create&store a dictionary for this enum, permanently or temporarily. // [Implementation off-topic.] var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary, EnumCacheExpiration); return enumDictionary.TryGetValue(value.Trim(), out result); } private static Dictionary CreateEnumDictionary() { return Enum.GetValues(typeof(T)) .Cast() .ToDictionary(value => value.ToSsortingng(), value => value, SsortingngComparer.OrdinalIgnoreCase); } 

Enum.Parse est votre ami:

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

Vous pouvez étendre la réponse acceptée avec une valeur par défaut pour éviter les exceptions:

 public static T ParseEnum(ssortingng 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); 

Nous ne pouvions pas supposer une entrée parfaitement valide et avons suivi cette variante de la réponse de @ Keith:

 public static TEnum ParseEnum(ssortingng value) where TEnum : struct { TEnum tmp; if (!Enum.TryParse(value, true, out tmp)) { tmp = new TEnum(); } return tmp; } 
 // str.ToEnum() T static ToEnum(this ssortingng str) { return (T) Enum.Parse(typeof(T), str); } 

Analyse la chaîne à TEnum sans try / catch et sans la méthode TryParse () à partir de .NET 4.5

 ///  /// Parses ssortingng to TEnum without try/catch and .NET 4.5 TryParse() ///  public static bool TryParseToEnum(ssortingng probablyEnumAsSsortingng_, out TEnum enumValue_) where TEnum : struct { enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0); if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsSsortingng_)) return false; enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsSsortingng_); return true; } 

Code super simple en utilisant TryParse:

 var value = "Active"; StatusEnum status; if (!Enum.TryParse(value, out status)) status = StatusEnum.Unknown; 

J’aime la solution de la méthode d’extension ..

 namespace System { public static class SsortingngExtensions { public static bool TryParseAsEnum(this ssortingng value, out T output) where T : struct { T result; var isEnum = Enum.TryParse(value, out result); output = isEnum ? result : default(T); return isEnum; } } } 

Voici ci-dessous mon implémentation avec des tests.

 using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert; using static System.Console; private enum Counsortinges { NorthAmerica, Europe, Rusia, Brasil, China, Asia, Australia } [TestMethod] public void SsortingngExtensions_On_TryParseAsEnum() { var countryName = "Rusia"; Counsortinges country; var isCountry = countryName.TryParseAsEnum(out country); WriteLine(country); IsTrue(isCountry); AreEqual(Counsortinges.Rusia, country); countryName = "Don't exist"; isCountry = countryName.TryParseAsEnum(out country); WriteLine(country); IsFalse(isCountry); AreEqual(Counsortinges.NorthAmerica, country); // the 1rst one in the enumeration } 
 public static T ParseEnum(ssortingng value) //function declaration { return (T) Enum.Parse(typeof(T), value); } Importance imp = EnumUtil.ParseEnum("Active"); //function call 

==================== Un programme complet ====================

 using System; class Program { enum PetType { None, Cat = 1, Dog = 2 } static void Main() { // Possible user input: ssortingng value = "Dog"; // Try to convert the ssortingng 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. 

J’ai utilisé la classe (version fortement typée d’Enum avec des améliorations d’parsing et de performance). Je l’ai trouvé sur GitHub, et il devrait également fonctionner avec .NET 3.5. Il y a une surcharge de mémoire puisqu’il met en mémoire tampon un dictionnaire.

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

Le blogpost est Enums – Meilleure syntaxe, amélioration des performances et TryParse dans NET 3.5 .

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

Pour la performance, cela pourrait aider:

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

J’ai trouvé que le cas avec les valeurs enum qui ont la valeur EnumMember n’a pas été pris en compte. Alors on y va:

 using System.Runtime.Serialization; public static TEnum ToEnum(this ssortingng value, TEnum defaultValue) where TEnum : struct { if (ssortingng.IsNullOrEmpty(value)) { return defaultValue; } TEnum result; var enumType = typeof(TEnum); foreach (var enumName in Enum.GetNames(enumType)) { var fieldInfo = enumType.GetField(enumName); var enumMemberAtsortingbute = ((EnumMemberAtsortingbute[]) fieldInfo.GetCustomAtsortingbutes(typeof(EnumMemberAtsortingbute), true)).FirstOrDefault(); if (enumMemberAtsortingbute?.Value == value) { return Enum.TryParse(enumName, true, out result) ? result : defaultValue; } } return Enum.TryParse(value, true, out result) ? result : defaultValue; } 

Et exemple de cette énumération:

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

Vous devez utiliser Enum.Parse pour obtenir la valeur de l’object à partir de Enum, après cela, vous devez changer la valeur de l’object en valeur enum spécifique. La conversion en valeur enum peut être effectuée à l’aide de Convert.ChangeType. S’il vous plaît jeter un oeil sur l’extrait de code suivant

 public T ConvertSsortingngValueToEnum(ssortingng valueToParse){ return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T)); }