[c#] Trasmetti int enum in C #



Answers

Basta lanciarlo:

MyEnum e = (MyEnum)3;

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

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

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




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;



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

enum Importance
{}

Importance importance;

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



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



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






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



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.




Di seguito è 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;
        }



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

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

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



Related