web-dev-qa-db-fra.com

Convert.ChangeType et conversion en enums?

J'ai obtenu une valeur Int16 de la base de données et je dois la convertir en un type enum. Cela se fait malheureusement dans une couche du code qui en sait très peu sur les objets, sauf sur ce qu’elle peut recueillir par réflexion.

En tant que tel, il finit par appeler Convert.ChangeType qui échoue avec une exception de distribution invalide.

J'ai trouvé ce que je considère comme une solution de rechange malodorante, comme ceci:

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

Y a-t-il une meilleure façon de ne pas avoir à passer par cette opération String?

Voici un programme court, mais complet, qui peut être utilisé si quelqu'un doit expérimenter:

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

Enum.ToObject(.... est ce que vous cherchez!

C #

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

VB.NET

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

Si vous convertissez beaucoup Enum, essayez d'utiliser la classe suivante, cela vous fera économiser beaucoup de code.

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

Maintenant, au lieu d'écrire (StringComparison)Enum.ToObject(typeof(StringComparison), 5);, vous pouvez simplement écrire Enum<StringComparison>.ToObject(5);.

78
Peter

Si vous stockez une énumération dans un DataTable mais ne savez pas quelle colonne est une énumération et quelle est une chaîne/int, vous pouvez accéder à la valeur de cette façon:

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

Basé sur la réponse de @ Peter, voici la méthode de conversion de Nullable<int> à 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;
        }
}

Utiliser EnumUtils.TryParse<YourEnumType>(someNumber, out result) devient utile pour de nombreux scénarios. Par exemple, WebApi Controller dans Asp.NET ne dispose pas de protection par défaut contre les paramètres Enum non valides. Asp.NET utilisera simplement la valeur default(YourEnumType), même si certains transmettent null, -1000, 500000, "garbage string" ou ignorent totalement le paramètre. De plus, ModelState sera valable dans tous les cas. Une des solutions consiste donc à utiliser le type int? avec contrôle personnalisé. 

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
    }
0
Artru