Wie kann ein int
an eine enum
in C#?
So korrekt sollte es sein: YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString) OR YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourInt) -- Wie zutreffend.
Von einem int:
YourEnum foo = (YourEnum)yourInt;
Aus einer Zeichenkette:
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.")
}
Aktualisierung:
Von der Nummer aus können Sie auch
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
So korrekt sollte es sein: YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString) OR YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourInt) -- Wie zutreffend.
@FlySwat, was wäre, wenn YourEnum
ist dynamisch und wird nur zur Laufzeit bekannt sein, und was ich möchte, ist eine Konvertierung in Enum
?
@Shimmy. Wenn die Aufzählung nur zur Laufzeit bekannt ist, sollten Sie sie dynamisch halten. Typsicherheit (strong typing) kann ohnehin nur vom Compiler garantiert werden. Sie können ein Objekt zur Laufzeit nicht stark typisieren. Dem kommt man am nächsten, wenn man Generika verwendet, aber der generische Typ muss zur Kompilierzeit bekannt sein. T ToEnum<T>(int x) { return (T)x; }
aber es gibt keinen wirklichen Vorteil gegenüber dem direkten Gießen.
Werfen Sie es einfach:
MyEnum e = (MyEnum)3;
Sie können überprüfen, ob es in Reichweite ist, indem Sie Enum.IsDefined :
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Achten Sie darauf, dass Sie Enum.IsDefined nicht verwenden können, wenn Sie das Attribut Flags verwenden und der Wert eine Kombination von Flags ist, zum Beispiel: Keys.L | Keys.Control
Betreffend Enum.IsDefined
Aber seien Sie sich bewusst, dass dies gefährlich sein kann: msdn.microsoft.com/de-us/library/ms229025(VS.90).aspx
Ich bevorzuge diese Definition: "Gibt an, ob eine Konstante mit einem bestimmten Wert in einer bestimmten Aufzählung existiert" de MSDN
Alternativ können Sie auch eine Erweiterungsmethode anstelle eines Einzeilers verwenden:
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
Verwendung:
Color colorEnum = "Red".ToEnum<Color>();
OR
string color = "Red";
var colorEnum = color.ToEnum<Color>();
Für die Verarbeitung von Benutzereingaben ist es wahrscheinlich eine gute Idee, die Überladung von Enum.Parse aufzurufen, mit der Sie festlegen können, dass beim Vergleich NICHT zwischen Groß- und Kleinschreibung unterschieden wird (d. h. wenn ein Benutzer "rot" (Kleinbuchstaben) eingibt, würde der obige Code ohne diese Änderung abstürzen).
Ich denke, um eine vollständige Antwort zu erhalten, müssen die Leute wissen, wie Enums intern in .NET funktionieren.
Wie etwas funktioniert
Ein Enum in .NET ist eine Struktur, die einen Satz von Werten (Feldern) einem Basistyp zuordnet (der Standard ist int
). Sie können jedoch den Integraltyp wählen, dem Ihre Aufzählung zugeordnet ist:
public enum Foo : short
In diesem Fall wird die Aufzählung auf die Datei short
Datentyp, d. h. er wird im Speicher als short gespeichert und verhält sich wie ein short, wenn Sie ihn casten und verwenden.
Aus der Sicht der AWL sieht eine (normale, int) Enum 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 Sie hier beachten sollten, ist, dass die value__
wird getrennt von den Aufzählungswerten gespeichert. Im Fall der Aufzählung Foo
oben, die Art der value__
ist int16. Das bedeutet im Grunde, dass Sie in einer Aufzählung speichern können, was immer Sie wollen, solange die Typen übereinstimmen .
An dieser Stelle möchte ich darauf hinweisen, dass System.Enum
ist ein Wertetyp, was im Grunde bedeutet, dass BarFlag
belegt 4 Bytes im Speicher und Foo
nimmt 2 -- z.B. die Größe des zugrundeliegenden Typs (eigentlich ist es komplizierter als das, aber hey...).
Die Antwort
Wenn Sie also eine Ganzzahl haben, die Sie einer Aufzählung zuordnen wollen, muss die Laufzeitumgebung nur zwei Dinge tun: die 4 Bytes kopieren und einen anderen Namen vergeben (den Namen der Aufzählung). Das Kopieren erfolgt implizit, da die Daten als Werttyp gespeichert werden. Das bedeutet, dass Sie bei Verwendung von nicht verwaltetem Code Enums und Integers einfach austauschen können, ohne Daten zu kopieren.
Um die Sicherheit zu gewährleisten, ist es meiner Meinung nach am besten, wenn wissen, dass die zugrundeliegenden Typen identisch oder implizit konvertierbar sind und um sicherzustellen, dass die Enum-Werte existieren (sie werden standardmäßig nicht überprüft!).
Um zu sehen, wie das funktioniert, probieren Sie den folgenden Code aus:
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 das Werfen nach e2
funktioniert auch! Aus der obigen Compiler-Perspektive macht dies Sinn: Die value__
wird einfach mit 5 oder 6 gefüllt, und wenn Console.WriteLine
ruft auf. ToString()
der Name von e1
aufgelöst wird, während der Name von e2
ist nicht.
Wenn Sie das nicht beabsichtigen, verwenden Sie Enum.IsDefined(typeof(MyEnum), 6)
um zu prüfen, ob der Wert, den Sie casten, einer definierten Aufzählung entspricht.
Beachten Sie auch, dass ich den zugrundeliegenden Typ der Aufzählung explizit angebe, auch wenn der Compiler dies tatsächlich überprüft. Ich tue dies, um sicherzustellen, dass ich später keine Überraschungen erlebe. Um diese Überraschungen in Aktion zu sehen, können Sie den folgenden Code verwenden (tatsächlich habe ich das schon oft in Datenbankcode gesehen):
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();
}
Mir ist klar, dass dies ein alter Beitrag ist, aber wie erlangt man dieses Niveau an Wissen in C#? Ist dies aus dem Lesen durch die C #-Spezifikation?
@Rolan Ich wünschte manchmal, mehr Leute würden das fragen :-) Um ehrlich zu sein, ich weiß es nicht wirklich; ich versuche zu verstehen, wie die Dinge funktionieren und hole mir Informationen, wo immer ich sie bekommen kann. Ich habe den C#-Standard gelesen, aber ich dekompiliere auch regelmäßig Code mit Reflector (ich schaue mir sogar oft den x86-Assembler-Code an) und mache viele kleine Experimente. Auch das Wissen über andere Sprachen ist in diesem Fall hilfreich; ich beschäftige mich jetzt seit etwa 30 Jahren mit CS, und irgendwann werden bestimmte Dinge "logisch" - z. B. sollte ein Enum integrale Typen haben, weil sonst die Interoperabilität nicht mehr gegeben ist (oder die Leistung den Bach runtergeht).
Ich glaube, der Schlüssel zu einer guten Softwareentwicklung ist das Wissen, wie etwas funktioniert. Für mich bedeutet das, dass ich, wenn ich einen Code schreibe, weiß, wie er sich z. B. auf Prozessoroperationen und Speicherzugriffe auswirkt. Wenn Sie fragen, wie man dieses Niveau erreichen kann, würde ich vorschlagen, eine Menge kleiner Testfälle zu erstellen, sie immer schwieriger zu machen, jedes Mal zu versuchen, das Ergebnis vorherzusagen, und sie anschließend zu testen (einschließlich Dekompilierung usw.). Nachdem man alle Details und alle Eigenschaften herausgefunden hat, kann man überprüfen, ob man es in der (langweiligen) Norm richtig gemacht hat. Zumindest wäre das mein Ansatz.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.