4 Stimmen

Wie lässt sich der dargestellte Typ eines Enum-Werts bestimmen?

Betrachten Sie die folgenden beiden Enums:

enum MyEnum1 {
    Value1 = 1,
    Value2 = 2,
    Value3 = 3
}

enum MyEnum2 {
     Value1 = 'a',
     Value2 = 'b',
     Value3 = 'c'
}

Ich kann den physischen Wert, der durch diese Enum-Werte dargestellt wird, durch explizites Casting abrufen, ((int)MyEnum1.Value2) == 2 o ((char)MyEnum2.Value2) == 'b' Was aber, wenn ich die char-Darstellung oder die int-Darstellung erhalten möchte, ohne vorher den Typ zu kennen, in den ich umwandeln muss?

Ist es möglich, den zugrundeliegenden Wert eines Enums ohne einen Cast zu erhalten oder ist es zumindest programmatisch möglich, den korrekten Typ des zugrundeliegenden Wertes zu bestimmen?

12voto

Jon Skeet Punkte 1325502

Der zugrunde liegende Wert dieser beiden Enums ist int . Sie nutzen einfach die Tatsache, dass es eine implizite Konvertierung von char zu int im zweiten Fall.

Wenn Sie sich zum Beispiel die zweite Aufzählung in Reflector ansehen, sehen Sie so etwas wie diese:

internal enum MyEnum2
{
    Value1 = 0x61,
    Value2 = 0x62,
    Value3 = 0x63
}

EDIT: Wenn Sie einen anderen zugrundeliegenden Typ wünschen, müssen Sie ihn angeben, z. B.

public enum Foo : long
{
}

Allerdings nur byte , sbyte , short , ushort , int , uint , long y ulong sind gültige zugrunde liegende Aufzählungstypen.

8voto

Jordão Punkte 53117

Alle Enums müssen einen der folgenden Typen in ihrer Deklaration verwenden: byte , sbyte , short , ushort , int , uint , long o ulong . So geben Sie einen Typ an:

enum MyEnum3 : long {
  Value1 = 5L,
  Value2 = 9L,
  Value3 = long.MaxValue
}

Wenn Sie keinen Typ angeben, ist der Standardwert int .

Leider können Sie nicht angeben char als zugrunde liegender Typ. Sie könnten diese "Erweiterung" als benutzerdefiniertes Attribut erstellen:

[AttributeUsage(AttributeTargets.Enum)]
public class CharAttribute : Attribute { }

[Char] enum MyEnum2 {
  Value1 = 'a',
  Value2 = 'b',
  Value3 = 'c'
}

Und dann eine Klasse wie diese:

public static class EnumEx {
  public static Type GetUnderlyingType(Type enumType) {
    if (!enumType.IsEnum) throw new ArgumentException();
    if (enumType.GetCustomAttributes(typeof(CharAttribute), false).Length > 0) {
      return typeof(char);
    }
    return Enum.GetUnderlyingType(enumType);
  }
  public static object ConvertToUnderlyingType(object enumValue) {
    return Convert.ChangeType(enumValue,
      GetUnderlyingType(enumValue.GetType()));
  }
}

(Nebenbei bemerkt, die Methode Enum.GetUnderlyingType scheint das Gesuchte zu sein, aber es kommt nicht zurück char weil man in der Sprache keine Char-Enums haben kann).

Auf diese Weise können Sie zu Ihrem erweiterten Begriff von char enums gelangen:

var value3 = EnumEx.ConvertToUnderlyingType(MyEnum2.Value3);
Console.WriteLine(value3);

Damit wird gedruckt c an die Konsole.

Achten Sie auf den zugrundeliegenden Typ und die Werte Ihrer Char-Enums, sie sollten idealerweise in eine char zur Vermeidung von Konvertierungsfehlern (Überläufen). Die sicheren Typen sind 16 Bit breit (genau wie char ) oder weniger: byte , sbyte , short o ushort . Andere Typen sind in Ordnung, wenn die Werte in der Aufzählung ohne Präzisionsverlust in 16-Bit-Zeichen umgewandelt werden können (wie im obigen Beispiel).

Die Verwendung der Standardeinstellung ( int ) zugrundeliegenden Typ und Char-Literale als Enum-Werte (die implizit konvertierbar sind in int ) ist gut genug.

UPDATE :

Sie können ein char enum in F# deklarieren:

namespace Drawing

type Color =
   | Red = 'r'
   | Green = 'g'
   | Blue = 'b'

In C# können Sie es wie folgt verwenden:

Console.WriteLine(Enum.GetUnderlyingType(typeof(Color)));

Und es wird gedruckt System.Char .

Aber ... C# wird sich beschweren, wenn Sie versuchen, seine Werte zu verwenden. Dies:

Console.WriteLine(Color.Red.ToString());

Ergibt einen Compilerfehler:

Fehler CS0570: 'Drawing.Color.Red' wird von der Sprache nicht unterstützt

In VB.NET gibt es keinen Kompilierungsfehler, aber es gibt einen Laufzeitfehler von Enum.GetName . Es scheint, dass die Laufzeitumgebung nicht darauf vorbereitet ist, mit Char-Enums umzugehen. Dies ist ein Auszug aus dieser Methode (aus Reflector):

if (((!type.IsEnum && (type != intType)) && ((type != typeof(short)) && (type != typeof(ushort)))) && (((type != typeof(byte)) && (type != typeof(sbyte))) && (((type != typeof(uint)) && (type != typeof(long))) && (type != typeof(ulong)))))
  {
    throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
  }

Es wird nicht nur geprüft, ob der Typ ein Enum ist, sondern auch, ob es sich um einen der oben genannten zugrundeliegenden Typen handelt (für die char keine Option ist). Sie sollten also in F# keine Char-Enums erstellen. Sie könnten den von mir beschriebenen Ansatz der "Erweiterung" verwenden.

1voto

Bryan Punkte 2739

Und enum ist hinter den Kulissen einfach ein int-Typ. Sie können es in long, byte und einige andere ändern, aber sie müssen Zahlen sein. Char funktioniert hier nur, weil es einfach in einen int geändert werden kann. Es tut mir leid, aber ich glaube nicht, dass dies möglich ist.

0voto

Paul Rivera Punkte 525

Versuchen Sie dies, es funktioniert bei mir:

public static bool IsCharEnum(this Type T)
{
    var enumType = T.IsNullableEnum() ? Nullable.GetUnderlyingType(T) : T;
    if (!enumType.IsEnum) return false;
    try
    {
        return ((int[])Enum.GetValues(enumType)).All(i => char.IsLetter((char)i));
    }
    catch
    {
        return false;
    }
}

public static bool IsNullableEnum(this Type T)
{
    var u = Nullable.GetUnderlyingType(T);
    return (u != null) && u.IsEnum;
}

Fügen Sie diesen Code zu einer Erweiterungsklasse hinzu, dann können Sie ihn als verwenden:

if (propValue.GetType().IsCharEnum())
{
    propValue = ((char)Convert.ToInt32(propValue)).ToString();
}

Wenn propValue vom Typ MyEnum2 ist, wird der Wert in ein Zeichen geändert und lautet 'a', 'b' oder 'c'.

CodeJaeger.com

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.

Powered by:

X