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!

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?


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.


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 :)


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.


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

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


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?


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


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


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
 */

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

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>()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.