Pregunta

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

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

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

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

pero eso no es un código válido.

¿Fue útil?

Solución

En .NET y central .NET >4 no hay un genérico método parse:

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

Esto también incluye C#7 nuevo en línea out las variables, de modo que esto hace el intento-el análisis, la conversión explícita de tipo enum y inicializa+rellena el myStatus variable.

Si usted tiene acceso a C#7 y la última .La RED, 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 con esto:

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

Entonces que puedo hacer:

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

Una alternativa propuesta en los comentarios es para agregar una extensión, la cual es bastante simple:

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

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

Por último, es posible que desee tener un defecto enum si la cadena no puede ser analizado:

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

Lo que hace la llamada:

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

Sin embargo, me gustaría tener cuidado al añadir un método de extensión como esta string como (sin espacio de nombres de control) aparecerá en todas las instancias de string que sean titulares de una enumeración o no (así que 1234.ToString().ToEnum(StatusEnum.None) sería válido, pero sin sentido) .Suele ser la mejor manera de evitar la confusión de Microsoft core clases con métodos adicionales que sólo se aplican en contextos específicos, a menos que su equipo de desarrollo tiene una muy buena comprensión de lo que esas extensiones.

Otros consejos

Uso Enum.TryParse<T>(String, T) (≥ .NET 4.0):

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

Se puede simplificar aún más con C# 7.0 parámetro de tipo inline:

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 en la otra dirección.)

Si usted necesita para convertir cadenas a las Enumeraciones en el rendimiento sensible código, su mejor apuesta es crear un Dictionary<String,YourEnum> en el inicio y el uso que hacemos de las conversiones.

Estás buscando Enum.Analizar.

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

Puede utilizar los 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 usted puede llamar por el código de abajo (aquí, FilterType es un tipo de enumeración):

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

Así que si usted tenía un enum nombre del estado de ánimo tendría este aspecto:

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

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

CUIDADO:

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

Enum.(Try)Parse() acepta varios, separados por comas los argumentos, y las combina con el binario 'o' |.No se puede deshabilitar esta y en mi opinión, casi nunca se desee.

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

Incluso si Three no estaba definida, x aún así consigue int valor 3.Que es aún peor:Enum.Parse() puede dar un valor que no está aún definido para el enum!

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

Además, como se ha mencionado 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<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);
    }

Enum.Analizar es tu amigo:

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

Puede ampliar la aceptó responder con un valor por defecto 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;
    }
}

A continuación, se llame como:

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

No podíamos asumir perfectamente válido de entrada, y fue con esta variación de @Keith respuesta:

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;
}
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}

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

Super simple de código mediante el uso de TryParse:

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;

Me gusta el método de extensión de la solució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í debajo de mi aplicació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<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.

He utilizado la clase (con establecimiento inflexible de la versión de Enum con el análisis y mejoras de rendimiento).Me lo encontré en GitHub, y se debe trabajar para .NET 3.5 demasiado.Tiene algunas de sobrecarga de la memoria, ya que los búferes de un diccionario.

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

La publicación del blog es Las enumeraciones – Mejor sintaxis, la mejora del rendimiento y TryParse en NET 3.5.

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

Para el rendimiento, esto podría ayudar a:

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

He encontrado que aquí el caso de la enumeración de los valores que han EnumMember valor no fue considerado.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 el ejemplo de que la enumeración:

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

Tiene el uso de la Enumeración.Analizar para obtener el valor del objeto de Enumeración, después de que usted tiene que cambiar el valor del objeto específico el valor de enumeración.Casting para el valor de enumeración se puede hacer mediante el uso de Convertir.ChangeType.Por favor, eche un vistazo en el siguiente fragmento de código

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

Pruebe 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 usted puede enviar cada cadena y su conjunto Enum.Si su Enum los datos que usted quería, retorno que como su Enum tipo.

        <Extension()>
    Public Function ToEnum(Of TEnum)(ByVal value As String, ByVal defaultValue As TEnum) As TEnum
        If String.IsNullOrEmpty(value) Then
            Return defaultValue
        End If

        Return [Enum].Parse(GetType(TEnum), value, True)
    End Function
public TEnum ToEnum<TEnum>(this string value, TEnum defaultValue){
if (string.IsNullOrEmpty(value))
    return defaultValue;

return Enum.Parse(typeof(TEnum), value, true);}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top