2009-01-27 11 views
99

Mam następujący kod:C# Iterowanie przez wyliczenie? (Indeksowanie System.Array)

// 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]); 
} 

Jednak, nie mogę wartości indeksu. Czy istnieje prostszy sposób na zrobienie tego?

A może przegapiłem coś całkowicie!

+0

Możesz sprawdzić [tajniki C# teksty stałe] (http://www.codeducky.org/ins-outs-c-enums/), który opisuje jak uzyskać wpisane IEnumerable przy użyciu GetValues ​​() i Cast() – ChaseMedallion

Odpowiedz

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

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

Można też rzucić System.Array który jest zwracany:

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

Ale można mieć pewność, że getValues ​​zwraca wartości w tej samej kolejności jak GetNames Zwraca nazwy?

+3

"Ale czy możesz mieć pewność, że GetValues ​​zwraca wartości w tej samej kolejności, w jakiej GetNames zwraca nazwy?" - To bardzo dobry punkt i coś, na co jeszcze muszę odpowiedzieć! Myślę, że twoje pierwsze rozwiązanie zapewne zapewniłoby niezawodny sposób dopasowania wartości i łańcuchów. –

+0

Witam, widziałem wcześniej wzmiankę o podejrzeniu "niedopasowania indeksów" występującego podczas tego; jednak, muszę jeszcze odkryć, czy to naprawdę jest problem, czy nie? Czy istnieją jakieś ostateczne przypadki, w których to założenie może pójść nie tak? Dzięki! – Funka

+0

Prawdopodobnie chcesz rzucić drugi "val" do int, jeśli chcesz rozwiązać problem niedopasowania wartości, jak w 'Enum.GetName (typeof (MyEnum), val), (int) val)' w którym wyjście zapewnia wyliczenie imię i nazwisko. – Greg

3

A co z używaniem pętli foreach, może mógłbyś z tym pracować?

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

coś takiego może być?

+0

Dowiedziałem się o tym ... ale muszę uzyskać dostęp do obu nazw i wartości w "sync" ... powiedzieć, że nazwy [2] są sparowane z wartościami [2] i Nie jestem pewien, jak to osiągnąć w pętli foreach! –

+0

Dodałem przykład - zobacz, czy to pomaga. – TWith2Sugars

30

Trzeba oddać tablicę - zwrócona tablica jest faktycznie od żądanego typu, tj myEnum[] jeśli poprosisz o typeof(myEnum):

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

Następnie values[0] itp

8

Można rzucać tej tablicy na inny rodzaje tablic:

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

lub jeśli chcesz wartości:

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

Można iteracyjne te odlewane tablice oczywiście :)

6

Jak o liście słowniku?

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

i oczywiście można zmienić typ wartości słownika na cokolwiek Twoje wartości są enum.

+0

Myślę, że to byłaby droga, ale niestety enum jest w obszarze kodu, nad którym nie mam kontroli! –

0

Oto prosty sposób wykonać iterację dodanego obiektu ENUM

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

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

Next 
+1

Myślę, że OP poprosił o C#. –

4

Oto kolejny. Mieliśmy potrzebę podania przyjaznych nazw dla naszych wartości EnumValues. Użyliśmy System.ComponentModel.DescriptionAttribute, aby pokazać niestandardową wartość ciągu dla każdej wartości wyliczeniowej.

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 Use

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



    static void Main(string[] args) 
    { 

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

będzie zakończyć powrocie "coś 1", "Something 2"

+0

Tylko dobrze, jeśli opisy są statyczne ... jeśli opisy muszą się zmieniać w zależności od instancji, to podejście to nie zadziała. – Llyle

4

Innym rozwiązaniem, z ciekawych możliwości:

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

Notatka mentalna: zwiększ plon –

2

można uprościć to za pomocą ciągów formatów. W wiadomościach o użytkowaniu używam następującego fragmentu:

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

Specyfikator formatu D formatuje wartość wyliczenia jako dziesiętną. Istnieje również specyfikator X, który daje wynik w postaci szesnastkowej.

Specyfikator G formatuje wyliczenie jako ciąg znaków. Jeśli atrybut Flags zostanie zastosowany do wyliczenia, obsługiwane będą również połączone wartości. Istnieje specyfikator F, który działa tak, jakby Flagi były zawsze obecne.

Zobacz Enum.Format().

3

Stare pytanie, ale nieco czystsze podejście przy użyciu LINQ na .Cast<>()

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

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

w wynikach Enum.GetValues, casting do int daje wartość liczbową. Używanie ToString() tworzy przyjazną nazwę. Nie są potrzebne żadne inne wywołania do Enum.GetName.

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