¿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 HTML select que contiene los valores de una enumeración. Cuando se publica la página, quiero recoger el valor (que será en forma de cadena) y convertirlo al valor de 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.

Author: Kirill Kobelev, 2008-08-19

20 answers

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 inline out de C#7, por lo que hace el try-parse, la conversión al tipo de enumeración explícita 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 más):

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

Tiendo a simplificar esto con:

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

Entonces puedo hacer: {[15]]}

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

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

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

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

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

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

Que hace que este sea el llamado:

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

Sin embargo, tendría cuidado de agregar un método de extensión como este a string ya que (sin control de espacio de nombres) aparecerá en todas las instancias de string si tienen una enumeración o no (así que 1234.ToString().ToEnum(StatusEnum.None) sería 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 tenga una muy buena comprensión de lo que hacen esas extensiones.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-16 16:58:04

Uso Enum.TryParse<T>(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 inlining de C# 7.0:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-14 16:20:56

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 para el otro lado.)

Si necesita convertir cadenas a Enumeraciones en código sensible al rendimiento, su mejor opción es crear un Dictionary<String,YourEnum> al inicio y usarlo para realizar sus conversiones.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-02 02:27:07

Estás buscando 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-30 12:37:12

Puedes usar métodos de extensión ahora:

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

Y puedes llamarlos por el siguiente código (aquí, FilterType es un tipo de enumeración):

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-30 12:40:29
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

Así que si tuvieras una enumeración llamada 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());
 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 12:58:57

CUIDADO:

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

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

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

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

No quisiera experimentar las consecuencias de los usuarios, voluntariamente o no, desencadenando este comportamiento.

Además, como han mencionado otros, el rendimiento es menos que ideal para grandes enum, es decir, lineal en el número de valores posibles.

Sugiero lo siguiente:

    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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-22 08:21:54

Enum.Parse es tu amigo:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-30 12:37:32

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

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

Entonces lo llamas así:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-30 12:42:52

No podíamos asumir una entrada perfectamente válida, y fuimos con esta variación de la respuesta 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
Author: gap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-05 15:06:47

Analiza string a TEnum sin try / catch y sin el método TryParse() 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
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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-30 12:46:11

Prueba este ejemplo:

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

En este ejemplo puede enviar cada cadena, y establecer su Enum. Si su Enum tenía los datos que quería, devuélvalos como su tipo 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-01 15:28:38

Código súper simple usando 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-25 02:30:35

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

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

Aquí abajo 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
        }
 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
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 Completo Programa De====================

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-18 05:28:07

Utilicé class (versión fuertemente tipeada 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 en búfer un diccionario.

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

El blogpost es Enumeraciones - Mejor sintaxis, mejor rendimiento y TryParse en NET 3.5.

Y código: 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-30 16:33:43

Para el rendimiento esto podría ayudar:

    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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-22 14:10:58

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

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

Y ejemplo de esa enumeración:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-04 16:40:31

Tienes que usar Enum.Analice para obtener el valor del objeto de Enum, después de eso tiene que cambiar el valor del objeto a un valor de enum específico. La conversión al valor de enumeración se puede hacer usando Convert.Tipo de cambio. Por favor, eche un vistazo al siguiente fragmento de código

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-12 12:11:01