Question Cast int pour enum en C #


Comment un int être jeté à un enum en C #?


2565
2017-08-27 03:58


origine


Réponses:


D'une chaîne:

YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);
// the foo.ToString().Contains(",") check is necessary for enumerations marked with an [Flags] attribute
if (!Enum.IsDefined(typeof(YourEnum), foo) && !foo.ToString().Contains(","))
  throw new InvalidOperationException($"{yourString} is not an underlying value of the YourEnum enumeration.")

D'un int:

YourEnum foo = (YourEnum)yourInt;

Mettre à jour:

De numéro, vous pouvez également

YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);

3115
2017-08-27 03:59



Juste le jeter:

MyEnum e = (MyEnum)3;

Vous pouvez vérifier si c'est dans la gamme en utilisant Enum.IsDefined:

if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }

718
2017-08-27 04:01



Vous pouvez également utiliser une méthode d'extension au lieu d'une seule ligne:

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

Usage:

Color colorEnum = "Red".ToEnum<Color>();

OU

string color = "Red";
var colorEnum = color.ToEnum<Color>();

197
2017-11-11 13:27



Je pense que pour avoir une réponse complète, les gens doivent savoir comment fonctionnent les enums en interne .NET.

Comment ça fonctionne

Une énumération dans .NET est une structure qui mappe un ensemble de valeurs (champs) à un type de base (la valeur par défaut est int). Cependant, vous pouvez réellement choisir le type intégral auquel votre énumération correspond:

public enum Foo : short

Dans ce cas, l'énumération est mappée au short type de données, ce qui signifie qu'il sera stocké dans la mémoire comme un court et se comportera comme un court lorsque vous lancez et l'utilisez.

Si vous le regardez d'un point de vue IL, une enum (normal, int) ressemble à ceci:

.class public auto ansi serializable sealed BarFlag extends System.Enum
{
    .custom instance void System.FlagsAttribute::.ctor()
    .custom instance void ComVisibleAttribute::.ctor(bool) = { bool(true) }

    .field public static literal valuetype BarFlag AllFlags = int32(0x3fff)
    .field public static literal valuetype BarFlag Foo1 = int32(1)
    .field public static literal valuetype BarFlag Foo2 = int32(0x2000)

    // and so on for all flags or enum values

    .field public specialname rtspecialname int32 value__
}

Ce qui devrait attirer votre attention ici, c'est que le value__ est stocké séparément des valeurs enum. Dans le cas de l'enum Foo ci-dessus, le type de value__ est int16. Cela signifie essentiellement que vous pouvez stocker ce que vous voulez dans une énumération, tant que les types correspondent.

À ce stade, je voudrais souligner que System.Enum est un type de valeur, ce qui signifie essentiellement que BarFlag prendra 4 octets en mémoire et Foo prendra 2 - par ex. la taille du type sous-jacent (c'est en fait plus compliqué que ça, mais bon ...).

La réponse

Donc, si vous avez un nombre entier que vous voulez mapper à une énumération, le moteur d'exécution doit seulement faire 2 choses: copier les 4 octets et le nommer quelque chose d'autre (le nom de l'énumération). La copie est implicite parce que les données sont stockées en tant que type de valeur - cela signifie essentiellement que si vous utilisez du code non géré, vous pouvez simplement échanger des énumérations et des entiers sans copier de données.

Pour le rendre sûr, je pense que c'est une bonne pratique savoir que les types sous-jacents sont les mêmes ou implicitement convertibles et pour s'assurer que les valeurs enum existent (elles ne sont pas vérifiées par défaut!).

Pour voir comment cela fonctionne, essayez le code suivant:

public enum MyEnum : int
{
    Foo = 1,
    Bar = 2,
    Mek = 5
}

static void Main(string[] args)
{
    var e1 = (MyEnum)5;
    var e2 = (MyEnum)6;

    Console.WriteLine("{0} {1}", e1, e2);
    Console.ReadLine();
}

Notez que le casting vers e2 fonctionne aussi! Du point de vue du compilateur ci-dessus, cela a du sens: le value__ champ est simplement rempli avec 5 ou 6 et quand Console.WriteLine appels ToString(), le nom de e1 est résolu alors que le nom de e2 n'est pas.

Si ce n'est pas ce que vous vouliez, utilisez Enum.IsDefined(typeof(MyEnum), 6) pour vérifier si la valeur que vous lancez correspond à une énumération définie.

Notez également que je suis explicite sur le type sous-jacent de l'énumération, même si le compilateur vérifie réellement cela. Je fais cela pour m'assurer de ne pas avoir de surprises sur la route. Pour voir ces surprises en action, vous pouvez utiliser le code suivant (en fait, j'ai vu cela se produire beaucoup dans le code de la base de données):

public enum MyEnum : short
{
    Mek = 5
}

static void Main(string[] args)
{
    var e1 = (MyEnum)32769; // will not compile, out of bounds for a short

    object o = 5;
    var e2 = (MyEnum)o;     // will throw at runtime, because o is of type int

    Console.WriteLine("{0} {1}", e1, e2);
    Console.ReadLine();
}

116
2018-04-03 07:39



Prenons l'exemple suivant:

int one = 1;
MyEnum e = (MyEnum)one;

89
2017-08-27 04:00



J'utilise ce morceau de code pour lancer int à mon énumération:

if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }

Je trouve que c'est la meilleure solution.


54
2017-10-21 10:05



Voici une belle classe d'utilité pour Enums

public static class EnumHelper
{
    public static int[] ToIntArray<T>(T[] value)
    {
        int[] result = new int[value.Length];
        for (int i = 0; i < value.Length; i++)
            result[i] = Convert.ToInt32(value[i]);
        return result;
    }

    public static T[] FromIntArray<T>(int[] value) 
    {
        T[] result = new T[value.Length];
        for (int i = 0; i < value.Length; i++)
            result[i] = (T)Enum.ToObject(typeof(T),value[i]);
        return result;
    }


    internal static T Parse<T>(string value, T defaultValue)
    {
        if (Enum.IsDefined(typeof(T), value))
            return (T) Enum.Parse(typeof (T), value);

        int num;
        if(int.TryParse(value,out num))
        {
            if (Enum.IsDefined(typeof(T), num))
                return (T)Enum.ToObject(typeof(T), num);
        }

        return defaultValue;
    }
}

44
2017-09-07 04:42



Si vous êtes prêt pour le 4.0 .NET Cadre, il y a un nouveau Enum.TryParse () fonction qui est très utile et joue bien avec l'attribut [Flags]. Voir Enum.TryParse, méthode (String, TEnum%)


37
2017-11-01 14:58



Pour les valeurs numériques, cela est plus sûr car il retournera un objet, peu importe quoi:

public static class EnumEx
{
    static public bool TryConvert<T>(int value, out T result)
    {
        result = default(T);
        bool success = Enum.IsDefined(typeof(T), value);
        if (success)
        {
            result = (T)Enum.ToObject(typeof(T), value);
        }
        return success;
    }
}

37
2018-02-21 15:22