Domanda Trasmetti int enum in C #


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


2564
2017-08-27 03:58


origine


risposte:


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;

Aggiornare:

Dal numero puoi anche

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

3115
2017-08-27 03:59



Basta lanciarlo:

MyEnum e = (MyEnum)3;

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

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

718
2017-08-27 04:01



In alternativa, usa un metodo di estensione invece di una linea singola:

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

Uso:

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

O

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

197
2017-11-11 13:27



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 (l'impostazione predefinita è int). Tuttavia, puoi effettivamente scegliere il tipo integrale che il tuo enum esegue su:

public enum Foo : short

In questo caso l'enum è mappato al short tipo di dati, 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 value__ è int16. Questo in pratica significa che puoi memorizzare ciò che vuoi in un enum, finché i tipi corrispondono.

A questo punto vorrei segnalarlo System.Enum è un tipo di valore, che in pratica significa che BarFlag occuperà 4 byte in memoria e Foo occuperà 2 - ad es. 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 per 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();
}

Si noti che il casting 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 è risolto mentre il nome di e2 non è.

Se non è quello che intendi, usa Enum.IsDefined(typeof(MyEnum), 6) per verificare se il valore su cui si sta eseguendo la mappatura è 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();
}

116
2018-04-03 07:39



Prendi il seguente esempio:

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

89
2017-08-27 04:00



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.


54
2017-10-21 10:05



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

44
2017-09-07 04:42



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


37
2017-11-01 14:58



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

37
2018-02-21 15:22



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

25
2018-04-13 20:13