C # Durch eine Aufzählung iterieren? (Indizieren eines System.Array)

113

Ich habe folgenden Code:

// Obtain the string names of all the elements within myEnum 
String[] names = Enum.GetNames( typeof( myEnum ) );

// Obtain the values of all the elements within myEnum 
Array values = Enum.GetValues( typeof( myEnum ) );

// Print the names and values to file
for ( int i = 0; i < names.Length; i++ )
{
    print( names[i], values[i] ); 
}

Ich kann jedoch keine Werte indizieren. Gibt es einen einfacheren Weg, dies zu tun?

Oder habe ich etwas ganz verpasst!

TK.
quelle

Antworten:

204
Array values = Enum.GetValues(typeof(myEnum));

foreach( MyEnum val in values )
{
   Console.WriteLine (String.Format("{0}: {1}", Enum.GetName(typeof(MyEnum), val), val));
}

Oder Sie können das zurückgegebene System.Array umwandeln:

string[] names = Enum.GetNames(typeof(MyEnum));
MyEnum[] values = (MyEnum[])Enum.GetValues(typeof(MyEnum));

for( int i = 0; i < names.Length; i++ )
{
    print(names[i], values[i]);
}

Können Sie jedoch sicher sein, dass GetValues ​​die Werte in derselben Reihenfolge zurückgibt, in der GetNames die Namen zurückgibt?

Frederik Gheysels
quelle
3
"Aber können Sie sicher sein, dass GetValues ​​die Werte in derselben Reihenfolge zurückgibt, in der GetNames die Namen zurückgibt?" - Dies ist ein sehr guter Punkt und etwas, das ich noch nicht angesprochen habe! Ich denke, Ihre erste Lösung würde wahrscheinlich eine Möglichkeit bieten, Werte und Zeichenfolgen zuverlässig abzugleichen
TK.
Hallo, ich habe bereits zuvor den Verdacht gesehen, dass dabei "Index-Mismatching" auftritt. Ich muss jedoch noch herausfinden, ob dies wirklich ein Problem ist oder nicht. Gibt es endgültige Fälle, in denen diese Annahme schief gehen könnte? Vielen Dank!
Funka
Sie möchten wahrscheinlich das zweite "val" in ein int umwandeln, wenn Sie die Wertinkongruenz beheben möchten, Enum.GetName(typeof(MyEnum), val), (int)val)in der die Ausgabe den Namen und die Nummer der Aufzählung enthält.
Greg
GetValues ​​und GetNames werden in derselben Reihenfolge zurückgegeben, nämlich: "Die Elemente des Rückgabewert-Arrays werden nach den Binärwerten der aufgezählten Konstanten (dh nach ihrer vorzeichenlosen Größe) sortiert."
Russell Borogove
Ich glaube, Sie können LINQ auch direkt verwenden, indem Sie Cast<T>das Ergebnis aufrufen :Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...
Jocull
33

Sie müssen das Array umwandeln - das zurückgegebene Array ist tatsächlich vom angeforderten Typ, dh myEnum[]wenn Sie fragen typeof(myEnum):

myEnum[] values = (myEnum[]) Enum.GetValues(typeof(myEnum));

Dann values[0]usw.

Marc Gravell
quelle
9

Sie können dieses Array in verschiedene Arten von Arrays umwandeln:

myEnum[] values = (myEnum[])Enum.GetValues(typeof(myEnum));

oder wenn Sie die ganzzahligen Werte wollen:

int[] values = (int[])Enum.GetValues(typeof(myEnum));

Sie können diese gegossenen Arrays natürlich iterieren :)

Arcturus
quelle
7

Wie wäre es mit einer Wörterbuchliste?

Dictionary<string, int> list = new Dictionary<string, int>();
foreach( var item in Enum.GetNames(typeof(MyEnum)) )
{
    list.Add(item, (int)Enum.Parse(typeof(MyEnum), item));
}

und natürlich können Sie den Wörterbuchwerttyp auf Ihre Aufzählungswerte ändern.

mrtaikandi
quelle
Ich denke, dass dies der richtige Weg wäre, aber leider befindet sich die Aufzählung in einem Codebereich, über den ich keine Kontrolle habe!
TK.
1
Die einzige Lösung, die ich gefunden habe, die die tatsächlichen ganzzahligen Aufzählungswerte erhält!
SharpC
5

Eine andere Lösung mit interessanten Möglichkeiten:

enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }

static class Helpers
{
public static IEnumerable<Days> AllDays(Days First)
{
  if (First == Days.Monday)
  {
     yield return Days.Monday;
     yield return Days.Tuesday;
     yield return Days.Wednesday;
     yield return Days.Thursday;
     yield return Days.Friday;
     yield return Days.Saturday;
     yield return Days.Sunday;
  } 

  if (First == Days.Saturday)
  {
     yield return Days.Saturday;
     yield return Days.Sunday;
     yield return Days.Monday;
     yield return Days.Tuesday;
     yield return Days.Wednesday;
     yield return Days.Thursday;
     yield return Days.Friday;
  } 
}
Paul
quelle
4

Hier ist noch einer. Wir mussten unseren EnumValues ​​freundliche Namen geben. Wir haben das System.ComponentModel.DescriptionAttribute verwendet, um einen benutzerdefinierten Zeichenfolgenwert für jeden Aufzählungswert anzuzeigen.

public static class StaticClass
{
    public static string GetEnumDescription(Enum currentEnum)
    {
        string description = String.Empty;
        DescriptionAttribute da;

        FieldInfo fi = currentEnum.GetType().
                    GetField(currentEnum.ToString());
        da = (DescriptionAttribute)Attribute.GetCustomAttribute(fi,
                    typeof(DescriptionAttribute));
        if (da != null)
            description = da.Description;
        else
            description = currentEnum.ToString();

        return description;
    }

    public static List<string> GetEnumFormattedNames<TEnum>()
    {
        var enumType = typeof(TEnum);
        if (enumType == typeof(Enum))
            throw new ArgumentException("typeof(TEnum) == System.Enum", "TEnum");

        if (!(enumType.IsEnum))
            throw new ArgumentException(String.Format("typeof({0}).IsEnum == false", enumType), "TEnum");

        List<string> formattedNames = new List<string>();
        var list = Enum.GetValues(enumType).OfType<TEnum>().ToList<TEnum>();

        foreach (TEnum item in list)
        {
            formattedNames.Add(GetEnumDescription(item as Enum));
        }

        return formattedNames;
    }
}

In Benutzung

 public enum TestEnum
 { 
        [Description("Something 1")]
        Dr = 0,
        [Description("Something 2")]
        Mr = 1
 }



    static void Main(string[] args)
    {

        var vals = StaticClass.GetEnumFormattedNames<TestEnum>();
    }

Dies endet mit der Rückgabe von "Something 1", "Something 2".

Kevin Castle
quelle
1
Nur gut, wenn die Beschreibungen statisch sind ... Wenn sich Ihre Beschreibungen auf Instanzbasis ändern müssen, funktioniert dieser Ansatz nicht.
Llyle
3

Was ist mit einer foreach-Schleife? Vielleicht könnten Sie damit arbeiten?

  int i = 0;
  foreach (var o in values)
  {
    print(names[i], o);
    i++;
  }

so etwas vielleicht?

TWith2Sugars
quelle
Ich habe darüber nachgedacht ... aber ich muss sowohl auf Namen als auch auf Werte in 'Sync' zugreifen können ... sagen, die Namen [2] sind mit Werten [2] gepaart, und ich bin mir nicht sicher, wie ich dies erreichen kann eine foreach Schleife!
TK.
Ich habe ein Beispiel hinzugefügt - sehen Sie, ob das hilft.
TWith2Sugars
3

Alte Frage, aber ein etwas sauberer Ansatz mit LINQs .Cast<>()

var values = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>();

foreach(var val in values)
{
    Console.WriteLine("Member: {0}",val.ToString());     
}
3Dave
quelle
2

Das Array verfügt über eine GetValue (Int32) -Methode, mit der Sie den Wert an einem angegebenen Index abrufen können.

Array.GetValue

Luftpolsterfolie
quelle
2

Sie können dies mithilfe von Formatzeichenfolgen vereinfachen. Ich verwende das folgende Snippet in Nutzungsnachrichten:

writer.WriteLine("Exit codes are a combination of the following:");
foreach (ExitCodes value in Enum.GetValues(typeof(ExitCodes)))
{
    writer.WriteLine("   {0,4:D}: {0:G}", value);
}

Der D-Formatbezeichner formatiert den Aufzählungswert als Dezimalzahl. Es gibt auch einen X-Bezeichner, der eine hexadezimale Ausgabe liefert.

Der G-Bezeichner formatiert eine Aufzählung als Zeichenfolge. Wenn das Flags-Attribut auf die Aufzählung angewendet wird, werden auch kombinierte Werte unterstützt. Es gibt einen F-Bezeichner, der so wirkt, als ob Flags immer vorhanden sind.

Siehe Enum.Format ().

Frank Szczerba
quelle
2

In den Enum.GetValues-Ergebnissen erzeugt das Umwandeln in int den numerischen Wert. Die Verwendung von ToString () erzeugt den Anzeigenamen. Es sind keine weiteren Aufrufe von Enum.GetName erforderlich.

public enum MyEnum
{
    FirstWord,
    SecondWord,
    Another = 5
};

// later in some method  

 StringBuilder sb = new StringBuilder();
 foreach (var val in Enum.GetValues(typeof(MyEnum))) {
   int numberValue = (int)val;
   string friendyName = val.ToString();
   sb.Append("Enum number " + numberValue + " has the name " + friendyName + "\n");
 }
 File.WriteAllText(@"C:\temp\myfile.txt", sb.ToString());

 // Produces the output file contents:
 /*
 Enum number 0 has the name FirstWord
 Enum number 1 has the name SecondWord
 Enum number 5 has the name Another
 */
Mike Wodarczyk
quelle
0

Hier ist eine einfache Möglichkeit, Ihr benutzerdefiniertes Enum-Objekt zu durchlaufen

For Each enumValue As Integer In [Enum].GetValues(GetType(MyEnum))

     Print([Enum].GetName(GetType(MyEnum), enumValue).ToString)

Next
Chev
quelle
1
Ich denke, OP hat nach C # gefragt.
jm.
0

Alte Frage, aber die Antwort von 3Dave lieferte den einfachsten Ansatz. Ich brauchte eine kleine Hilfsmethode, um ein SQL-Skript zu generieren und einen Enum-Wert in der Datenbank zum Debuggen zu dekodieren. Es hat super funktioniert:

    public static string EnumToCheater<T>() {
        var sql = "";
        foreach (var enumValue in Enum.GetValues(typeof(T)))
            sql += $@"when {(int) enumValue} then '{enumValue}' ";
        return $@"case ?? {sql}else '??' end,";
    }

Ich habe es in einer statischen Methode, daher ist die Verwendung:

var cheater = MyStaticClass.EnumToCheater<MyEnum>()
Wade Hatler
quelle