¿Cómo debo convertir una cadena a una enumeración en C #?

¿Cuál es la mejor manera de convertir una cadena a un valor de enumeración en C #?

Tengo una etiqueta de selección HTML que contiene los valores de una enumeración. Cuando se publique la página, quiero recoger el valor (que será en forma de una cadena) y convertirlo al valor de la enumeración.

En un mundo ideal, podría hacer algo como esto:

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

pero ese no es un código válido

En .NET Core y .NET> 4, hay un método de análisis genérico :

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

Esto también incluye las nuevas variables de out línea de C # 7, por lo tanto, esto hace el análisis de prueba, la conversión al tipo de myStatus explícito e inicializa + rellena la variable myStatus .

Si tiene acceso a C # 7 y al último .NET, esta es la mejor manera.

Respuesta original

En .NET es bastante feo (hasta 4 o superior):

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

Tiendo a simplificar esto con:

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

Entonces puedo hacer:

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

Una opción sugerida en los comentarios es agregar una extensión, que es bastante simple:

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

Finalmente, es posible que desee tener una enumeración predeterminada para usar si la cadena no se puede analizar:

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

Lo que hace que esta sea la llamada:

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

Sin embargo, sería cuidadoso agregar un método de extensión como este a la string como (sin control de espacio de nombres) aparecerá en todas las instancias de string si contienen una enumeración o no (por lo que 1234.ToString().ToEnum(StatusEnum.None) sería ser válido pero sin sentido). A menudo es mejor evitar saturar las clases principales de Microsoft con métodos adicionales que solo se aplican en contextos muy específicos a menos que todo su equipo de desarrollo comprenda muy bien lo que hacen esas extensiones.

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

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

Se puede simplificar aún más con el tipo de parámetro de C # 7.0 en línea:

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

Tenga en cuenta que el rendimiento de Enum.Parse () es horrible, porque se implementa a través de la reflexión. (Lo mismo es cierto de Enum.ToString, que va por el otro lado).

Si necesita convertir cadenas a Enums en código sensible al rendimiento, su mejor opción es crear un Dictionary al inicio y usarlo para hacer sus conversiones.

Está buscando Enum.Parse .

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

Puede usar métodos de extensión ahora:

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

Y puede llamarlos por el siguiente código (aquí, FilterType es un tipo enum):

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

Entonces, si tuvieras un enum llamado mood, se vería así:

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

TENER CUIDADO:

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

Enum.(Try)Parse() acepta múltiples argumentos separados por comas y los combina con ‘o’ binario | . No puede desactivar esto y, en mi opinión, casi nunca lo quiere.

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

Incluso si Three no se definió, x aún obtendría int value 3 . Eso es aún peor: ¡Enum.Parse () puede darte un valor que ni siquiera está definido para la enumeración!

No me gustaría experimentar las consecuencias de los usuarios, voluntaria o involuntariamente, desencadenando este comportamiento.

Además, como se mencionó por otros, el rendimiento es menos que ideal para grandes enumeraciones, es decir, lineal en el número de valores posibles.

Sugiero lo siguiente:

  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 es tu amigo:

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

Puede extender la respuesta aceptada con un valor predeterminado para evitar excepciones:

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

Entonces lo llamas así:

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

No pudimos asumir una entrada perfectamente válida, y fuimos con esta variación de la respuesta de @ 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); } 

Analiza cadenas en TEnum sin try / catch y sin el método TryParse () de .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; } 

Código super simple usando TryParse:

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

Me gusta la solución del método de extensión …

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

Aquí debajo de mi implementación con pruebas.

 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 progtwig 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. 

Utilicé la clase (versión fuertemente tipada de Enum con análisis y mejoras de rendimiento). Lo encontré en GitHub, y debería funcionar para .NET 3.5 también. Tiene cierta sobrecarga de memoria ya que almacena un diccionario.

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

El blogpost es Enums – Mejor syntax, mejor rendimiento y TryParse en NET 3.5 .

Y código: https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs

Para el rendimiento, esto podría ayudar:

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

Descubrí que aquí no se consideró el caso con valores enum que tienen el valor EnumMember. Así que, aquí vamos:

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

Y ejemplo de esa enumeración:

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

Tienes que usar Enum.Parse para obtener el valor del objeto de Enum, después de eso tienes que cambiar el valor del objeto a un valor enum específico. Se puede hacer conversión a enum value usando Convert.ChangeType. Por favor, eche un vistazo al siguiente fragmento de código

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