Come dovrei convertire una stringa in enum in C #?

Qual è il modo migliore per convertire una stringa in un valore di enumerazione in C #?

Ho un tag select HTML contenente i valori di un’enumerazione. Quando viene pubblicata la pagina, voglio prelevare il valore (che sarà sotto forma di stringa) e convertirlo nel valore di enumerazione.

In un mondo ideale, potrei fare qualcosa del genere:

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

ma quello non è un codice valido.

In .NET Core e .NET> 4 esiste un metodo di analisi generico :

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

Ciò include anche le nuove variabili inline out C # 7, quindi questo fa il try-parse, la conversione al tipo enum esplicito e inizializza + popola la variabile myStatus .

Se hai accesso a C # 7 e all’ultimo .NET, questo è il modo migliore.

Risposta originale

In .NET è piuttosto brutto (fino a 4 o sopra):

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

Tendo a semplificarlo con:

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

Quindi posso fare:

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

Un’opzione suggerita nei commenti è di aggiungere un’estensione, che è abbastanza semplice:

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

Infine, potresti voler avere un enum predefinito da usare se la stringa non può essere analizzata:

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

Il che rende questa la chiamata:

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

Tuttavia, farei attenzione ad aggiungere un metodo di estensione come questo a string come (senza controllo dello spazio dei nomi) che apparirà su tutte le istanze di string indipendentemente dal fatto che abbiano o meno enum (quindi 1234.ToString().ToEnum(StatusEnum.None) essere valido ma senza senso). Spesso è meglio evitare di ingombrare le classi principali di Microsoft con metodi aggiuntivi che si applicano solo in contesti molto specifici, a meno che l’intero team di sviluppo non abbia una buona conoscenza di ciò che fanno queste estensioni.

Utilizzare Enum.TryParse(String, T) (≥ .NET 4.0):

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

Può essere ulteriormente semplificato con l’ inlining del tipo di parametro C # 7.0:

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

Si noti che le prestazioni di Enum.Parse () sono orribili, perché sono implementate tramite reflection. (Lo stesso vale per Enum.ToString, che va dall’altra parte).

Se devi convertire stringhe in Enums in un codice sensibile al rendimento, la soluzione migliore è creare un Dictionary all’avvio e utilizzarlo per eseguire le conversioni.

Stai cercando Enum.Parse .

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

Puoi ora utilizzare i metodi di estensione :

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

E puoi chiamarli con il codice seguente (qui, FilterType è un tipo enum):

 FilterType filterType = type.ToEnum(); 
 object Enum.Parse(System.Type enumType, string value, bool ignoreCase); 

Quindi se tu avessi un enum chiamato mood, sembrerebbe questo:

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

ATTENZIONE:

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

Enum.(Try)Parse() accetta più argomenti separati da virgole e li combina con binario “o” | . Non puoi disabilitare questo e secondo me non lo vuoi quasi mai.

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

Anche se Three non fosse definito, x otterrebbe comunque il valore int 3 . È ancora peggio: Enum.Parse () può darti un valore che non è nemmeno definito per l’enum!

Non vorrei sperimentare le conseguenze degli utenti, volenti o nolenti, che triggersno questo comportamento.

Inoltre, come menzionato da altri, le prestazioni non sono l’ideale per grandi enumerazioni, ossia lineari nel numero di valori possibili.

Suggerisco il seguente:

  public static bool TryParse(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, EnumCacheExpiration); return enumDictionary.TryGetValue(value.Trim(), out result); } private static Dictionary CreateEnumDictionary() { return Enum.GetValues(typeof(T)) .Cast() .ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase); } 

Enum.Parse è tuo amico:

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

È ansible estendere la risposta accettata con un valore predefinito per evitare eccezioni:

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

Quindi lo chiami come:

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

Non potevamo assumere input perfettamente validi e siamo andati con questa variazione della risposta di @ Keith:

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

Analizza la stringa su TEnum senza try / catch e senza il metodo TryParse () da .NET 4.5

 ///  /// Parses string to TEnum without try/catch and .NET 4.5 TryParse() ///  public static bool TryParseToEnum(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; } 

Codice super semplice con TryParse:

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

Mi piace la soluzione del metodo di estensione ..

 namespace System { public static class StringExtensions { public static bool TryParseAsEnum(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; } } } 

Qui sotto la mia implementazione con i test.

 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 } 
 public static T ParseEnum(string value) //function declaration { return (T) Enum.Parse(typeof(T), value); } Importance imp = EnumUtil.ParseEnum("Active"); //function call 

==================== Un programma completo ====================

 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. 

Ho usato la class (versione fortemente tipizzata di Enum con analisi e miglioramenti delle prestazioni). L’ho trovato su GitHub e dovrebbe funzionare anche per .NET 3.5. Ha un sovraccarico di memoria poiché bufferizza un dizionario.

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

Il blogpost è Enums: migliore syntax, prestazioni migliorate e TryParse in NET 3.5 .

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

Per prestazioni questo potrebbe aiutare:

  private static Dictionary> dicEnum = new Dictionary>(); public static T ToEnum(this string 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.ToString(), en); } else dic = dicEnum[t]; if (!dic.ContainsKey(value)) return defaultValue; else return (T)dic[value]; } 

Ho trovato che qui il caso con valori enum che hanno valore EnumMember non è stato considerato. Quindi eccoci qui:

 using System.Runtime.Serialization; public static TEnum ToEnum(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; } 

E esempio di quell’enumerazione:

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

È necessario utilizzare Enum.Parse per ottenere il valore dell’object da Enum, dopodiché è necessario modificare il valore dell’object su un valore enum specifico. La conversione al valore enum può essere eseguita utilizzando Convert.ChangeType. Si prega di dare un’occhiata al seguente snippet di codice

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