c# to c++ - Cast int à enum en C #




10 Answers

Il suffit de le lancer:

MyEnum e = (MyEnum)3;

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

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

Comment un int peut-il être converti en une enum en C #?




Je pense que pour obtenir une réponse complète, il faut que les gens sachent comment fonctionnent les enums 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 d'intégrale auquel votre énumération correspond:

public enum Foo : short

Dans ce cas, l'énumération est mappée sur le type de données short , ce qui signifie qu'elle sera stockée en mémoire sous forme de mémoire et se comportera comme telle lors de son utilisation.

Si vous le regardez d'un point de vue IL, un 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 est que la value__ est stockée 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, à condition que les types correspondent .

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

La réponse

Ainsi, si vous souhaitez mapper un entier sur une énumération, le moteur d'exécution ne doit effectuer que 2 choses: copier les 4 octets et lui attribuer un autre nom (le nom de l'énumération). La copie est implicite car les données sont stockées en tant que type de valeur. En d'autres termes, si vous utilisez du code non managé, vous pouvez simplement échanger des enum et des entiers sans copier les données.

Pour plus de sécurité, je pense qu'il est préférable de savoir que les types sous-jacents sont identiques ou implicitement convertibles et de s'assurer que les valeurs enum existent (elles ne sont pas coché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 la conversion en e2 fonctionne également! Du point de vue du compilateur ci-dessus, cela a du sens: le champ value__ est simplement rempli avec 5 ou 6 et lorsque Console.WriteLine appelle ToString() , le nom de e1 est résolu alors que le nom de e2 ne l’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 Enum.IsDefined(typeof(MyEnum), 6) correspondance avec une énumération définie.

Notez également que je suis explicite sur le type sous-jacent de l'énum, ​​même si le compilateur vérifie réellement cela. Je fais cela pour m'assurer de ne pas avoir de surprises par la suite. 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 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();
}



J'utilise ce morceau de code pour lancer int à mon enum:

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

Je trouve la meilleure solution.




Pour les valeurs numériques, cela est plus sûr car cela 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;
    }
}



Si vous avez un entier faisant office de masque binaire et pouvant représenter une ou plusieurs valeurs dans une énumération [Flags], vous pouvez utiliser ce code pour analyser les valeurs d'indicateur individuelles dans une liste:

for (var flagIterator = 0x1; flagIterator <= 0x80000000; flagIterator <<= 1)
{
    // Check to see if the current flag exists in the bit mask
    if ((intValue & flagIterator) != 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), flagIterator))
            ListOfEnumValues.Add((MyEnum)flagIterator);
    }
}



Il s'agit d'une méthode de conversion sécurisée avec une énumération de drapeaux:

public static bool TryConvertToEnum<T>(this int instance, out T result)
  where T: struct
{
  var enumType = typeof (T);
  if (!enumType.IsEnum)
  {
    throw new ArgumentException("The generic type must be an enum.");
  }
  var success = Enum.IsDefined(enumType, instance);
  if (success)
  {
    result = (T)Enum.ToObject(enumType, instance);
  }
  else
  {
    result = default(T);
  }
  return success;
}



Légèrement en m'éloignant de la question initiale, mais j'ai trouvé une réponse à la question Get int value of enum utile. Créez une classe statique avec public const int propriétés public const int , ce qui vous permet de facilement rassembler un ensemble de constantes int associées, sans avoir à les int 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;
}

De toute évidence, certaines fonctionnalités de type énumération seront perdues, mais pour stocker un grand nombre de constantes id de base de données, cela semble être une solution plutôt ordonnée.




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

enum Importance
{}

Importance importance;

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



Dans mon cas, je devais retourner l'énumération d'un service WCF. J'avais également besoin d'un nom convivial, pas seulement l'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 d'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();
        }
    }

La mise en oeuvre:

return EnumMember.ConvertToList<YourType>();



Je ne sais plus où j'obtiens la partie de cette extension enum, mais c'est à partir de . Je suis désolé pour cela! Mais j'ai pris celui-ci et l'ai modifié pour les énumérations avec les drapeaux. Pour les enums avec des drapeaux 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;





Related