Frage Cast int, um in C # aufzuzählen


Wie kann ein int zu einem geworfen werden enum in C #?


2565
2017-08-27 03:58


Ursprung


Antworten:


Aus einer Zeichenfolge:

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

Von einem int:

YourEnum foo = (YourEnum)yourInt;

Aktualisieren:

Von der Nummer können Sie auch

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

3115
2017-08-27 03:59



Einfach umwandeln:

MyEnum e = (MyEnum)3;

Sie können überprüfen, ob es in Reichweite ist Enum.IsDefined:

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

718
2017-08-27 04:01



Alternativ verwenden Sie eine Erweiterungsmethode anstelle eines Einzeilers:

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

Verwendung:

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

ODER

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

197
2017-11-11 13:27



Ich denke, um eine vollständige Antwort zu erhalten, müssen die Leute wissen, wie Enums intern in .NET arbeiten.

Wie Dinge funktionieren

Eine Enumeration in .NET ist eine Struktur, die einen Satz von Werten (Feldern) einem Basistyp zuordnet (der Standardwert ist int). Sie können jedoch auch den ganzzahligen Typ auswählen, dem Ihre enum zugeordnet ist:

public enum Foo : short

In diesem Fall wird die Enumeration auf die short Datentyp, was bedeutet, dass es als Short gespeichert wird und sich beim Cast und der Verwendung als Short verhält.

Wenn Sie es aus der Sicht von IL betrachten, sieht eine (normale, int) Enumeration wie folgt aus:

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

Was sollte Ihre Aufmerksamkeit hier darauf lenken, dass die value__ wird getrennt von den Enum-Werten gespeichert. Im Falle des Enums Foo oben, der Typ von value__ ist int16. Dies bedeutet im Grunde, dass Sie alles, was Sie wollen, in einem Enum speichern können, solange die Typen übereinstimmen.

An dieser Stelle möchte ich darauf hinweisen System.Enum ist ein Werttyp, der das bedeutet BarFlag belegt 4 Bytes im Speicher und Foo wird 2 - z.B. die Größe des zugrunde liegenden Typs (es ist eigentlich komplizierter als das, aber hey ...).

Die Antwort

Wenn Sie also eine Ganzzahl haben, die Sie einer Enumeration zuordnen möchten, muss die Laufzeit nur zwei Dinge tun: Kopieren Sie die 4 Bytes und benennen Sie sie mit etwas anderem (dem Namen der Enumeration). Das Kopieren ist implizit, da die Daten als Werttyp gespeichert werden. Dies bedeutet, dass Sie, wenn Sie nicht verwalteten Code verwenden, einfach Enums und Ganzzahlen austauschen können, ohne Daten zu kopieren.

Um es sicher zu machen, halte ich das für eine bewährte Methode wissen, dass die zugrunde liegenden Typen gleich oder implizit konvertierbar sind und um sicherzustellen, dass die enum-Werte existieren (sie sind standardmäßig nicht markiert!).

Versuchen Sie den folgenden Code, um zu sehen, wie das funktioniert:

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

Beachten Sie, dass Casting zu e2 funktioniert auch! Aus der Perspektive des Compilers ergibt das Sinn: das value__ Feld wird einfach mit 5 oder 6 gefüllt und wann Console.WriteLine Anrufe ToString(), der Name von e1 ist gelöst, während der Name von e2 ist nicht.

Wenn das nicht beabsichtigt ist, verwenden Sie Enum.IsDefined(typeof(MyEnum), 6) Überprüfen Sie, ob der Wert, den Sie werfen, einer definierten Aufzählung zugeordnet ist.

Beachten Sie auch, dass ich explizit über den zugrunde liegenden Typ der Enumeration bin, obwohl der Compiler dies tatsächlich überprüft. Ich mache das, um sicherzustellen, dass ich keine Überraschungen auf der Straße bekomme. Um diese Überraschungen in Aktion zu sehen, können Sie den folgenden Code verwenden (tatsächlich habe ich gesehen, dass dies häufig im Datenbankcode passiert):

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



Nehmen Sie das folgende Beispiel:

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

89
2017-08-27 04:00



Ich benutze diesen Code, um int in meine enum zu schreiben:

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

Ich finde es die beste Lösung.


54
2017-10-21 10:05



Unten ist eine nette Hilfsklasse für 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