70 votes

Convert.ChangeType et conversion en enums ?

J'ai reçu un Int16 à partir de la base de données, et nous devons la convertir en un type d'énumération. Cette opération est malheureusement effectuée dans une couche du code qui connaît très peu les objets, à l'exception de ce qu'elle peut recueillir par réflexion.

Ainsi, 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 contournement malodorante, comme ceci :

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

Existe-t-il une meilleure solution, pour ne pas avoir à passer par cette opération String ?

Voici un programme court, mais complet, qui peut être utilisé si quelqu'un a besoin d'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);
    }
}

1 votes

Aïe... Je dois arrêter d'essayer de répondre à ce genre de questions avant d'avoir pris mon café...

0 votes

Je vois maintenant que Console.WriteLine est aussi dans une couche qui n'a pas accès au type enum. J'ai complètement mal compris. J'ai supprimé ma réponse (stupide).

92voto

Peter Points 9636

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

C#

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

VB.NET

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

Si vous faites beaucoup de conversion d'Enum, essayez d'utiliser la classe suivante, elle vous permettra d'é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); .

4 votes

La légende ! Je ne connaissais pas ça. stackoverflow n'est-il pas génial ? ! :-)

0 votes

J'ai lutté pendant plus d'une heure avec un problème similaire et cela l'a résolu ! Un +1 bien mérité même deux ans après l'avoir posté ;)

1 votes

ToObject() semble autoriser des valeurs qui n'existent pas dans l'enum et également des valeurs en dehors de la plage du type sous-jacent : Enum.ToObject(typeof(IntEnumType), (long)Int32.MaxValue + 1)

0voto

Artru Points 737

En se basant sur la réponse de @Peter, voici la méthode pour Nullable<int> a Enum conversion :

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

Utilisation de EnumUtils.TryParse<YourEnumType>(someNumber, out result) devient utile pour de nombreux scénarios. Par exemple, le contrôleur WebApi dans Asp.NET n'a pas de protection par défaut contre les paramètres Enum invalides. Asp.NET utilisera simplement default(YourEnumType) valeur, même si certaines passes null , -1000 , 500000 , "garbage string" ou ignore totalement le paramètre. De plus, ModelState sera valide dans tous ces cas, donc une des solutions est d'utiliser int? type 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
    }

0voto

Cassova Points 151

Si vous stockez un enum dans un DataTable mais que vous ne savez pas quelle colonne est un enum et quelle colonne est une chaîne de caractères/un nombre entier, vous pouvez accéder à la valeur de cette manière :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X