Question

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

Était-ce utile?

La solution

À partir 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.")

À partir d'un int :

YourEnum foo = (YourEnum)yourInt;

Mise à jour:

À partir du numéro, vous pouvez également

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

Autres conseils

Lancez-le simplement :

MyEnum e = (MyEnum)3;

Vous pouvez vérifier s'il est à portée en utilisant Enum.IsDefined:

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

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

Je pense que pour obtenir une réponse complète, les gens doivent savoir comment fonctionnent les énumérations en interne dans .NET.

Comment ça marche

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é en mémoire sous forme de court-circuit et se comportera comme un court-circuit lorsque vous le diffuserez et l'utiliserez.

Si vous le regardez d'un point de vue IL, une énumération (normale, 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'énumération 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 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

Ainsi, si vous souhaitez mapper un entier à une énumération, le runtime n'a qu'à faire 2 choses :copiez les 4 octets et nommez-le autrement (le nom de l'énumération).La copie est implicite car les données sont stockées sous forme de type 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 les données.

Pour le rendre sûr, je pense que c'est une bonne pratique de savoir que les types sous-jacents sont identiques ou implicitement convertibles et pour s'assurer que les valeurs d'énumération 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 ça marche aussi !Du point de vue du compilateur ci-dessus, cela a du sens :le value__ Le 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 transtypez 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 le vérifie réellement.Je fais cela pour m'assurer de ne pas avoir de surprises plus tard.Pour voir ces surprises en action, vous pouvez utiliser le code suivant (en fait, j'ai souvent vu cela se produire dans le code de 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();
}

Prenons l'exemple suivant :

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

J'utilise ce morceau de code pour convertir un int en 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.

Vous trouverez ci-dessous une belle classe utilitaire 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;
    }
}

Pour les valeurs numériques, c'est plus sûr car cela renverra un objet quoi qu'il arrive :

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

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

Si vous disposez d'un entier qui agit comme un masque de bits et peut représenter une ou plusieurs valeurs dans une énumération [Flags], vous pouvez utiliser ce code pour analyser les valeurs individuelles des indicateurs dans une liste :

for (var flagIterator = 0; flagIterator < 32; flagIterator++)
{
    // Determine the bit value (1,2,4,...,Int32.MinValue)
    int bitValue = 1 << flagIterator;

    // Check to see if the current flag exists in the bit mask
    if ((intValue & bitValue) != 0)
    {
        // If the current flag exists in the enumeration, then we can add that value to the list
        // if the enumeration has that flag defined
        if (Enum.IsDefined(typeof(MyEnum), bitValue))
            Console.WriteLine((MyEnum)bitValue);
    }
}

Notez que cela suppose que le type sous-jacent du enum est un entier signé de 32 bits.S'il s'agissait d'un type numérique différent, vous devrez modifier le 32 codé en dur pour refléter les bits de ce type (ou le dériver par programme en utilisant Enum.GetUnderlyingType())

Parfois, vous avez un objet à MyEnum taper.Comme

var MyEnumType = typeof(MyEnumType);

Alors:

Enum.ToObject(typeof(MyEnum), 3)

Il s'agit d'une méthode de conversion sécurisée prenant en compte l'énumération des drapeaux :

public static bool TryConvertToEnum<T>(this int instance, out T result)
  where T: Enum
{
  var enumType = typeof (T);
  var success = Enum.IsDefined(enumType, instance);
  if (success)
  {
    result = (T)Enum.ToObject(enumType, instance);
  }
  else
  {
    result = default(T);
  }
  return success;
}

enter image description here

Pour convertir une chaîne en ENUM ou un int en constante ENUM, nous devons utiliser la fonction Enum.Parse.Voici une vidéo youtube https://www.youtube.com/watch?v=4nhx4VwdRDk qui démontre en fait avec une chaîne et il en va de même pour int.

Le code se présente comme indiqué ci-dessous, où "rouge" est la chaîne et "MyColors" est la couleur ENUM qui a les constantes de couleur.

MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");

Je m'éloigne un peu de la question initiale, mais j'ai trouvé une réponse à la question Stack Overflow Récupérer la valeur int de l'énumération utile.Créez une classe statique avec public const int propriétés, vous permettant de rassembler facilement un tas de propriétés liées int constantes, et ne pas avoir à les convertir en int lors de leur utilisation.

public static class Question
{
    public static readonly int Role = 2;
    public static readonly int ProjectFunding = 3;
    public static readonly int TotalEmployee = 4;
    public static readonly int NumberOfServers = 5;
    public static readonly int TopBusinessConcern = 6;
}

Évidemment, certaines fonctionnalités du type enum seront perdues, mais pour stocker un tas de constantes d'identification de base de données, cela semble être une solution assez simple.

Cela analyse des entiers ou des chaînes en une énumération cible avec une correspondance partielle dans dot.NET 4.0 en utilisant des génériques comme dans la classe utilitaire de Tawani ci-dessus.Je l'utilise pour convertir des variables de commutateur de ligne de commande qui peuvent être incomplètes.Puisqu'une énumération ne peut pas être nulle, vous devez logiquement fournir une valeur par défaut.On peut l'appeler ainsi :

var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);

Voici le code :

using System;

public class EnumParser<T> where T : struct
{
    public static T Parse(int toParse, T defaultVal)
    {
        return Parse(toParse + "", defaultVal);
    }
    public static T Parse(string toParse, T defaultVal) 
    {
        T enumVal = defaultVal;
        if (defaultVal is Enum && !String.IsNullOrEmpty(toParse))
        {
            int index;
            if (int.TryParse(toParse, out index))
            {
                Enum.TryParse(index + "", out enumVal);
            }
            else
            {
                if (!Enum.TryParse<T>(toParse + "", true, out enumVal))
                {
                    MatchPartialName(toParse, ref enumVal);
                }
            }
        }
        return enumVal;
    }

    public static void MatchPartialName(string toParse, ref T enumVal)
    {
        foreach (string member in enumVal.GetType().GetEnumNames())
        {
            if (member.ToLower().Contains(toParse.ToLower()))
            {
                if (Enum.TryParse<T>(member + "", out enumVal))
                {
                    break;
                }
            }
        }
    }
}

POUR VOTRE INFORMATION: La question concernait les entiers, que personne n'a mentionné, qui seront également explicitement convertis dans Enum.TryParse()

À partir d'une chaîne :(Enum.Parse est obsolète, utilisez Enum.TryParse)

enum Importance
{}

Importance importance;

if (Enum.TryParse(value, out importance))
{
}

Voici une méthode d'extension légèrement meilleure

public static string ToEnumString<TEnum>(this int enumValue)
        {
            var enumString = enumValue.ToString();
            if (Enum.IsDefined(typeof(TEnum), enumValue))
            {
                enumString = ((TEnum) Enum.ToObject(typeof (TEnum), enumValue)).ToString();
            }
            return enumString;
        }

Dans mon cas, je devais renvoyer l'énumération d'un service WCF.J'avais également besoin d'un nom convivial, pas seulement du enum.ToString().

Voici ma classe WCF.

[DataContract]
public class EnumMember
{
    [DataMember]
    public string Description { get; set; }

    [DataMember]
    public int Value { get; set; }

    public static List<EnumMember> ConvertToList<T>()
    {
        Type type = typeof(T);

        if (!type.IsEnum)
        {
            throw new ArgumentException("T must be of type enumeration.");
        }

        var members = new List<EnumMember>();

        foreach (string item in System.Enum.GetNames(type))
        {
            var enumType = System.Enum.Parse(type, item);

            members.Add(
                new EnumMember() { Description = enumType.GetDescriptionValue(), Value = ((IConvertible)enumType).ToInt32(null) });
        }

        return members;
    }
}

Voici la méthode Extension qui obtient la description de l'énumération.

    public static string GetDescriptionValue<T>(this T source)
    {
        FieldInfo fileInfo = source.GetType().GetField(source.ToString());
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fileInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);            

        if (attributes != null && attributes.Length > 0)
        {
            return attributes[0].Description;
        }
        else
        {
            return source.ToString();
        }
    }

Mise en œuvre:

return EnumMember.ConvertToList<YourType>();

Différentes manières de lancer vers et depuis Enum

enum orientation : byte
{
 north = 1,
 south = 2,
 east = 3,
 west = 4
}

class Program
{
  static void Main(string[] args)
  {
    orientation myDirection = orientation.north;
    Console.WriteLine(“myDirection = {0}”, myDirection); //output myDirection =north
    Console.WriteLine((byte)myDirection); //output 1

    string strDir = Convert.ToString(myDirection);
        Console.WriteLine(strDir); //output north

    string myString = “north”; //to convert string to Enum
    myDirection = (orientation)Enum.Parse(typeof(orientation),myString);


 }
}

Je ne sais plus où je récupère la partie de cette extension enum, mais elle vient de stackoverflow.Je suis désolé pour cela!Mais j'ai pris celui-ci et je l'ai modifié pour les énumérations avec Flags.Pour les énumérations avec Flags, j'ai fait ceci :

  public static class Enum<T> where T : struct
  {
     private static readonly IEnumerable<T> All = Enum.GetValues(typeof (T)).Cast<T>();
     private static readonly Dictionary<int, T> Values = All.ToDictionary(k => Convert.ToInt32(k));

     public static T? CastOrNull(int value)
     {
        T foundValue;
        if (Values.TryGetValue(value, out foundValue))
        {
           return foundValue;
        }

        // For enums with Flags-Attribut.
        try
        {
           bool isFlag = typeof(T).GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
           if (isFlag)
           {
              int existingIntValue = 0;

              foreach (T t in Enum.GetValues(typeof(T)))
              {
                 if ((value & Convert.ToInt32(t)) > 0)
                 {
                    existingIntValue |= Convert.ToInt32(t);
                 }
              }
              if (existingIntValue == 0)
              {
                 return null;
              }

              return (T)(Enum.Parse(typeof(T), existingIntValue.ToString(), true));
           }
        }
        catch (Exception)
        {
           return null;
        }
        return null;
     }
  }

Exemple:

[Flags]
public enum PetType
{
  None = 0, Dog = 1, Cat = 2, Fish = 4, Bird = 8, Reptile = 16, Other = 32
};

integer values 
1=Dog;
13= Dog | Fish | Bird;
96= Other;
128= Null;

Il peut vous aider à convertir toutes les données d'entrée en données souhaitées par l'utilisateur. énumération.Supposons que vous ayez une énumération comme ci-dessous qui, par défaut int.Veuillez ajouter un Défaut valeur au début de votre énumération.Qui est utilisé dans la méthode d'assistance lorsqu'aucune correspondance n'est trouvée avec la valeur d'entrée.

public enum FriendType  
{
    Default,
    Audio,
    Video,
    Image
}

public static class EnumHelper<T>
{
    public static T ConvertToEnum(dynamic value)
    {
        var result = default(T);
        var tempType = 0;

        //see Note below
        if (value != null &&
            int.TryParse(value.ToString(), out  tempType) && 
            Enum.IsDefined(typeof(T), tempType))
        {
            result = (T)Enum.ToObject(typeof(T), tempType); 
        }
        return result;
    }
}

N.B. : Ici, j'essaie d'analyser la valeur en int, car enum est par défaut intSi vous définissez une énumération comme ceci, ce qui est octet taper.

public enum MediaType : byte
{
    Default,
    Audio,
    Video,
    Image
} 

Vous devez modifier l'analyse de la méthode d'assistance à partir de

int.TryParse(value.ToString(), out  tempType)

à

byte.TryParse(value.ToString(), out tempType)

Je vérifie ma méthode pour les entrées suivantes

EnumHelper<FriendType>.ConvertToEnum(null);
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("-1");
EnumHelper<FriendType>.ConvertToEnum("6");
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("2");
EnumHelper<FriendType>.ConvertToEnum(-1);
EnumHelper<FriendType>.ConvertToEnum(0);
EnumHelper<FriendType>.ConvertToEnum(1);
EnumHelper<FriendType>.ConvertToEnum(9);

Désolé pour mon anglais

Voici une méthode d'extension qui convertit Int32 à Enum.

Il honore les indicateurs au niveau du bit même lorsque la valeur est supérieure au maximum possible.Par exemple, si vous avez une énumération avec des possibilités 1, 2, et 4, mais l'int est 9, il comprend que comme 1 en l'absence d'un 8.Cela vous permet d'effectuer des mises à jour de données avant les mises à jour de code.

   public static TEnum ToEnum<TEnum>(this int val) where TEnum : struct, IComparable, IFormattable, IConvertible
    {
        if (!typeof(TEnum).IsEnum)
        {
            return default(TEnum);
        }

        if (Enum.IsDefined(typeof(TEnum), val))
        {//if a straightforward single value, return that
            return (TEnum)Enum.ToObject(typeof(TEnum), val);
        }

        var candidates = Enum
            .GetValues(typeof(TEnum))
            .Cast<int>()
            .ToList();

        var isBitwise = candidates
            .Select((n, i) => {
                if (i < 2) return n == 0 || n == 1;
                return n / 2 == candidates[i - 1];
            })
            .All(y => y);

        var maxPossible = candidates.Sum();

        if (
            Enum.TryParse(val.ToString(), out TEnum asEnum)
            && (val <= maxPossible || !isBitwise)
        ){//if it can be parsed as a bitwise enum with multiple flags,
          //or is not bitwise, return the result of TryParse
            return asEnum;
        }

        //If the value is higher than all possible combinations,
        //remove the high imaginary values not accounted for in the enum
        var excess = Enumerable
            .Range(0, 32)
            .Select(n => (int)Math.Pow(2, n))
            .Where(n => n <= val && n > 0 && !candidates.Contains(n))
            .Sum();

        return Enum.TryParse((val - excess).ToString(), out asEnum) ? asEnum : default(TEnum);
    }

le moyen simple et clair de convertir un int en énumération en c# :

 public class Program
    {
        public enum Color : int
        {
            Blue = 0,
            Black = 1,
            Green = 2,
            Gray = 3,
            Yellow =4
        }

        public static void Main(string[] args)
        {
            //from string
            Console.WriteLine((Color) Enum.Parse(typeof(Color), "Green"));

            //from int
            Console.WriteLine((Color)2);

            //From number you can also
            Console.WriteLine((Color)Enum.ToObject(typeof(Color) ,2));
        }
    }

Vous utilisez simplement Conversion explicite Convertir int en énumération ou énumération en int

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((int)Number.three); //Output=3

            Console.WriteLine((Number)3);// Outout three
            Console.Read();
        }

        public enum Number 
        {
            Zero = 0,
            One = 1,
            Two = 2,
            three = 3           
        }
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top