Pergunta

Eu tenho um valor de Int16, a partir do banco de dados e precisa converter isso em um tipo enum. Esta é, infelizmente, feito de uma camada de código que sabe muito pouco sobre os objetos, exceto para o que pode reunir através da reflexão.

Como tal, ele acaba chamando Convert.ChangeType que falha com uma exceção de elenco inválido.

Eu encontrei o que eu considero uma solução alternativa mau cheiro, como este:

String name = Enum.GetName(destinationType, value);
Object enumValue = Enum.Parse(destinationType, name, false);

Existe uma maneira melhor, para que eu não tenho para percorrer esta operação de Cordas?

Aqui está uma pequena, mas completa, programa que pode ser usado se alguém necessidade de experimentar:

using System;

public class MyClass
{
    public enum DummyEnum
    {
        Value0,
        Value1
    }

    public static void Main()
    {
        Int16 value = 1;
        Type destinationType = typeof(DummyEnum);

        String name = Enum.GetName(destinationType, value);
        Object enumValue = Enum.Parse(destinationType, name, false);

        Console.WriteLine("" + value + " = " + enumValue);
    }
}
Foi útil?

Solução

Enum.ToObject(.... é o que você está procurando!

C #

StringComparison enumValue = (StringComparison)Enum.ToObject(typeof(StringComparison), 5);

VB.NET

Dim enumValue As StringComparison = CType([Enum].ToObject(GetType(StringComparison), 5), StringComparison)

Se você fizer um monte de Enum converter tente usar a seguinte classe que irá poupar-lhe um monte de código.

public class Enum<EnumType> where EnumType : struct, IConvertible
{

    /// <summary>
    /// Retrieves an array of the values of the constants in a specified enumeration.
    /// </summary>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType[] GetValues()
    {
        return (EnumType[])Enum.GetValues(typeof(EnumType));
    }

    /// <summary>
    /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType Parse(string name)
    {
        return (EnumType)Enum.Parse(typeof(EnumType), name);
    }

    /// <summary>
    /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
    /// </summary>
    /// <param name="name"></param>
    /// <param name="ignoreCase"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType Parse(string name, bool ignoreCase)
    {
        return (EnumType)Enum.Parse(typeof(EnumType), name, ignoreCase);
    }

    /// <summary>
    /// Converts the specified object with an integer value to an enumeration member.
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    public static EnumType ToObject(object value)
    {
        return (EnumType)Enum.ToObject(typeof(EnumType), value);
    }
}

Agora, em vez de escrever (StringComparison)Enum.ToObject(typeof(StringComparison), 5); você pode Enum<StringComparison>.ToObject(5); Basta escrever.

Outras dicas

Com base na resposta da @ Peter aqui é o método para Nullable<int> à conversão Enum:

public static class EnumUtils
{
        public static bool TryParse<TEnum>(int? value, out TEnum result)
            where TEnum: struct, IConvertible
        {
            if(!value.HasValue || !Enum.IsDefined(typeof(TEnum), value)){
                result = default(TEnum);
                return false;
            }
            result = (TEnum)Enum.ToObject(typeof(TEnum), value);
            return true;
        }
}

Usando EnumUtils.TryParse<YourEnumType>(someNumber, out result) torna-se útil para muitos cenários. Por exemplo, WebAPI Controller em Asp.NET não tem proteção padrão contra a enumeração inválido parâmetros. Asp.NET só vai usar o valor default(YourEnumType), mesmo que alguns passes null, -1000, 500000, "garbage string" ou ignora totalmente o parâmetro. Além disso, ModelState será válida em todos estes casos, por isso, uma das soluções é a utilização tipo int? com verificação feita sob encomenda

public class MyApiController: Controller
{
    [HttpGet]
    public IActionResult Get(int? myEnumParam){    
        MyEnumType myEnumParamParsed;
        if(!EnumUtils.TryParse<MyEnumType>(myEnumParam, out myEnumParamParsed)){
            return BadRequest($"Error: parameter '{nameof(myEnumParam)}' is not specified or incorrect");
        }      

        return this.Get(washingServiceTypeParsed);            
    }
    private IActionResult Get(MyEnumType myEnumParam){ 
       // here we can guarantee that myEnumParam is valid
    }

Se você estiver armazenando um Enum em um DataTable, mas não sei qual coluna é uma enumeração e que é uma cadeia / int, você pode acessar o valor da seguinte maneira:

foreach (DataRow dataRow in myDataTable.Rows)
{
    Trace.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
    foreach (DataColumn dataCol in myDataTable.Columns)
    {
        object v = dataRow[dataCol];
        Type t = dataCol.DataType;
        bool e = false;
        if (t.IsEnum) e = true;

        Trace.WriteLine((dataCol.ColumnName + ":").PadRight(30) +
            (e ? Enum.ToObject(t, v) : v));
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top