c# convert to - Trasmetti int enum in C #



10 Answers

Basta lanciarlo:

MyEnum e = (MyEnum)3;

È possibile verificare se è nell'intervallo utilizzando Enum.IsDefined . È Enum.IsDefined :

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

Come si può lanciare un int a un enum in C #?




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

Come funzionano le cose

Un enum in .NET è una struttura che mappa un insieme di valori (campi) in un tipo di base (il valore predefinito è int ). Tuttavia, puoi effettivamente scegliere il tipo integrale che il tuo enum esegue su:

public enum Foo : short

In questo caso, l'enum viene mappato sul tipo di dati short , il che significa che verrà archiviato in memoria come un cortocircuito e si comporterà come un corto quando lo lanci e lo usi.

Se lo guardi da un punto di vista di 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 vostra attenzione qui è che il value__ è memorizzato separatamente dai valori enum. Nel caso dell'enum Foo sopra, il tipo di valore value__ è int16. Ciò significa fondamentalmente che è possibile memorizzare ciò che si desidera in una enumerazione, purché i tipi corrispondano .

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

La risposta

Quindi, se si ha un numero intero che si desidera mappare a un enum, il runtime deve solo fare 2 cose: copiare i 4 byte e nominarlo qualcos'altro (il nome dell'enum). La copia è implicita perché i dati sono memorizzati come tipo di valore; in pratica, ciò significa che se si utilizza un codice non gestito, è possibile scambiare semplicemente enumerazioni e interi senza copiare i dati.

Per renderlo sicuro, penso che sia una buona pratica sapere che i tipi sottostanti sono uguali o implicitamente convertibili e garantire che i valori enum esistano (non sono controllati di default!).

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

Nota che anche casting in e2 funziona! Dal punto di vista del compilatore sopra questo ha senso: il campo value__ viene semplicemente riempito con 5 o 6 e quando Console.WriteLine chiama ToString() , il nome di e1 viene risolto mentre il nome di e2 non lo è.

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

Si noti inoltre che sono esplicito sul tipo sottostante dell'enumerazione, anche se il compilatore lo controlla effettivamente. Lo sto facendo per assicurarmi di non avere sorprese lungo la strada. Per vedere queste sorprese in azione, puoi usare il seguente codice (in realtà ho visto accadere molte cose 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();
}



Sto usando questo pezzo di codice per trasmettere int al mio enum:

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

La trovo la soluzione migliore.




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 si dispone di un numero intero che funge da maschera di bit e potrebbe rappresentare uno o più valori in un'enumerazione [Flags], è possibile utilizzare questo codice per analizzare i singoli valori di flag in un elenco:

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



Questo è un metodo di conversione sicura consapevole dell'enumerazione dei flag:

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



Un po 'di distanza dalla domanda originale, ma ho trovato una risposta alla domanda Ottieni un valore int da enum utile. Crea una classe statica con public const int proprietà public const int , che ti consentono di raccogliere facilmente un gruppo di costanti int correlate e di non doverle int a int quando le utilizzi.

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 delle funzionalità di tipo enum andranno perse, ma per la memorizzazione di una serie di costanti ID del database, sembra una soluzione piuttosto ordinata.




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

enum Importance
{}

Importance importance;

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



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

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

Ecco il metodo di estensione 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>();



Non so più dove ottengo la parte di questa estensione enum, ma è da . Mi dispiace per questo! Ma ho preso questo e l'ho modificato per enumerare con Flags. Per enumerare con le bandiere, 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;



Related