Domanda

Come può un int essere lanciato su un enum in C#?

È stato utile?

Soluzione

Da una stringa:

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

Da un int:

YourEnum foo = (YourEnum)yourInt;

Aggiornamento:

Dal numero puoi anche

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

Altri suggerimenti

Lancialo e basta:

MyEnum e = (MyEnum)3;

Puoi verificare se è nel raggio d'azione utilizzando Enum.IsDefined:

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

In alternativa, utilizza un metodo di estensione invece di una riga:

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

Utilizzo:

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

O

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

Penso che per ottenere una risposta completa, le persone devono sapere come funzionano le enumerazioni internamente in .NET.

Come funzionano le cose

Un'enumerazione in .NET è una struttura che associa un insieme di valori (campi) a un tipo di base (l'impostazione predefinita è int).Tuttavia, puoi effettivamente scegliere il tipo integrale a cui si associa la tua enumerazione:

public enum Foo : short

In questo caso l'enumerazione viene mappata su short tipo di dati, il che significa che verrà archiviato in memoria come cortometraggio e si comporterà come cortometraggio quando lo trasmetti e lo utilizzi.

Se lo guardi dal punto di vista IL, un enum (normale, int) assomiglia a questo:

.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__
}

Ciò che dovrebbe attirare la tua attenzione qui è che il value__ viene memorizzato separatamente dai valori enum.Nel caso dell'enum Foo sopra, il tipo di value__ è int16.Ciò significa sostanzialmente che puoi memorizzare tutto ciò che desideri in un'enumerazione, purché i tipi corrispondano.

A questo punto vorrei sottolinearlo System.Enum è un tipo di valore, il che in pratica significa questo BarFlag occuperà 4 byte in memoria e Foo ne occuperà 2 -- ad es.la dimensione del tipo sottostante (in realtà è più complicato di così, ma ehi...).

La risposta

Quindi, se hai un numero intero che vuoi mappare su un'enumerazione, il runtime deve fare solo 2 cose:copia i 4 byte e chiamali qualcos'altro (il nome dell'enum).La copia è implicita perché i dati vengono archiviati come tipo valore: ciò significa sostanzialmente che se si utilizza codice non gestito, è possibile semplicemente scambiare enumerazioni e numeri interi senza copiare i dati.

Per renderlo sicuro, penso che sia una buona pratica farlo sapere che i tipi sottostanti sono gli stessi o implicitamente convertibili e per garantire che i valori enum esistano (non sono controllati per impostazione predefinita!).

Per vedere come funziona, prova il seguente codice:

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

Tieni presente che trasmettere a e2 funziona anche!Dal punto di vista del compilatore sopra questo ha senso:IL value__ il campo viene semplicemente riempito con 5 o 6 e quando Console.WriteLine chiamate ToString(), il nome di e1 viene risolto mentre il nome di e2 non è.

Se non è quello che intendevi, usa Enum.IsDefined(typeof(MyEnum), 6) per verificare se il valore che stai trasmettendo è mappato su un'enumerazione definita.

Tieni inoltre presente che sono esplicito riguardo al tipo sottostante dell'enumerazione, anche se il compilatore lo controlla effettivamente.Lo faccio per assicurarmi di non incorrere in sorprese lungo la strada.Per vedere queste sorprese in azione, puoi utilizzare il seguente codice (in realtà l'ho visto accadere spesso nel codice del database):

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

Prendiamo il seguente esempio:

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

Sto usando questo pezzo di codice per eseguire il cast int della mia enumerazione:

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

Trovo che sia la soluzione migliore.

Di seguito è riportata una bella classe di utilità per 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;
    }
}

Per i valori numerici, questo è più sicuro poiché restituirà un oggetto indipendentemente da cosa:

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

Se sei pronto per il 4.0 .NETTO Quadro, c'è una novità Enum.TryParse() funzione che è molto utile e funziona bene con l'attributo [Flags].Vedere Metodo Enum.TryParse (Stringa, TEnum%)

Se hai un numero intero che funge da maschera di bit e potrebbe rappresentare uno o più valori in un'enumerazione [Flags], puoi utilizzare questo codice per analizzare i singoli valori dei flag in un elenco:

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

Tieni presente che ciò presuppone che il tipo sottostante di enum è un numero intero con segno a 32 bit.Se fosse un tipo numerico diverso, dovresti cambiare il 32 hardcoded per riflettere i bit in quel tipo (o derivarlo programmaticamente usando Enum.GetUnderlyingType())

A volte hai un oggetto da considerare MyEnum tipo.Come

var MyEnumType = typeof(MyEnumType);

Poi:

Enum.ToObject(typeof(MyEnum), 3)

Questo è un metodo di conversione sicuro che riconosce l'enumerazione dei flag:

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

Per convertire una stringa in ENUM o un int nella costante ENUM dobbiamo utilizzare la funzione Enum.Parse.Ecco un video di YouTube https://www.youtube.com/watch?v=4nhx4VwdRDk che in realtà dimostra con string e lo stesso vale per int.

Il codice è come mostrato di seguito dove "rosso" è la stringa e "MyColors" è il colore ENUM che ha le costanti del colore.

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

Mi sto allontanando leggermente dalla domanda originale, ma ho trovato una risposta alla domanda Stack Overflow Ottieni il valore int da enum utile.Crea una classe statica con public const int proprietà, che ti consentono di raccogliere facilmente un insieme di proprietà correlate int costanti, e quindi non è necessario eseguirne il cast int quando li si utilizza.

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

Ovviamente, alcune funzionalità del tipo enum andranno perse, ma per archiviare un sacco di costanti ID del database, sembra una soluzione abbastanza ordinata.

Analizza numeri interi o stringhe in un'enumerazione di destinazione con corrispondenza parziale in dot.NET 4.0 utilizzando generici come nella classe di utilità di Tawani sopra.Lo sto usando per convertire le variabili di commutazione della riga di comando che potrebbero essere incomplete.Poiché un'enumerazione non può essere nulla, dovresti logicamente fornire un valore predefinito.Si può chiamare così:

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

Ecco il codice:

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

PER TUA INFORMAZIONE: La domanda riguardava gli interi, che nessuno ha menzionato verranno convertiti esplicitamente anche in Enum.TryParse()

Da una stringa:(Enum.Parse non è aggiornato, utilizzare Enum.TryParse)

enum Importance
{}

Importance importance;

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

Di seguito è riportato un metodo di estensione leggermente migliore

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

Nel mio caso, dovevo restituire l'enumerazione da un servizio WCF.Avevo anche bisogno di un nome descrittivo, non solo di enum.ToString().

Ecco la mia lezione 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;
    }
}

Ecco il metodo Extension che ottiene la descrizione dall'enum.

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

Implementazione:

return EnumMember.ConvertToList<YourType>();

Diversi modi di lanciare verso e da 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);


 }
}

Non so più dove prendo la parte di questa estensione enum, ma proviene da StackOverflow.Mi dispiace per questo!Ma ho preso questo e l'ho modificato per le enumerazioni con Flags.Per le enumerazioni con Flags ho fatto questo:

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

Esempio:

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

Può aiutarti a convertire qualsiasi dato di input nell'utente desiderato enum.Supponiamo di avere un'enumerazione come di seguito, quale per impostazione predefinita int.Per favore aggiungi un Predefinito valore all'inizio della tua enum.Che viene utilizzato nel metodo helper quando non viene trovata alcuna corrispondenza con il valore di input.

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

NB: Qui provo ad analizzare il valore in int, perché enum è per impostazione predefinita intSe definisci enum in questo modo, che è byte tipo.

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

È necessario modificare l'analisi del metodo helper da

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

A

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

Controllo il mio metodo per seguire gli input

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

mi scusi per il mio inglese

Ecco un metodo di estensione che esegue il cast Int32 A Enum.

Rispetta i flag bit a bit anche quando il valore è superiore al massimo possibile.Ad esempio se hai un'enumerazione con possibilità 1, 2, E 4, ma l'int è 9, lo comprende come 1 in assenza di un 8.Ciò consente di effettuare aggiornamenti dei dati prima degli aggiornamenti del codice.

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

il modo semplice e chiaro per trasmettere un int a enum in 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));
        }
    }

Usa semplicemente Conversione esplicita Cast int su enum o enum su 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           
        }
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top