C # Iterazione attraverso un'enumerazione? (Indicizzazione di un System.Array)


113

Ho il codice seguente:

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

Tuttavia, non posso indicizzare i valori. C'è un modo più semplice per farlo?

O mi sono perso completamente qualcosa!

Risposte:


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

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

Oppure puoi eseguire il cast del System.Array che viene restituito:

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

Ma puoi essere sicuro che GetValues ​​restituisca i valori nello stesso ordine in cui GetNames restituisce i nomi?


3
"Ma puoi essere sicuro che GetValues ​​restituisca i valori nello stesso ordine in cui GetNames restituisce i nomi?" - Questo è un ottimo punto e qualcosa che devo ancora affrontare! Penso che la tua prima soluzione probabilmente fornirebbe un modo per abbinare valori e stringhe in modo affidabile
TK.

Ciao, ho già visto menzionare questo sospetto di "mancata corrispondenza dell'indice" che si verifica durante questa operazione; tuttavia, devo ancora scoprire se questa è davvero una preoccupazione o no? Ci sono casi definitivi in ​​cui questa ipotesi può andare storta? Grazie!
Funka

Probabilmente si desidera eseguire il cast della seconda "val" a un int, se si desidera risolvere i problemi di mancata corrispondenza dei valori come Enum.GetName(typeof(MyEnum), val), (int)val)in cui l'output fornisce il nome e il numero dell'enumerazione.
Greg

GetValues ​​e GetNames restituiscono nello stesso ordine, ovvero: "Gli elementi della matrice del valore restituito vengono ordinati in base ai valori binari delle costanti enumerate (ovvero, in base alla loro grandezza senza segno)."
Russell Borogove

Credo che tu possa anche usare LINQ direttamente chiamando Cast<T>il risultato:Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...
jocull

33

Devi eseguire il cast dell'array: l'array restituito è in realtà del tipo richiesto, cioè myEnum[]se chiedi typeof(myEnum):

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

Quindi values[0]ecc


9

Puoi eseguire il cast di tale array su diversi tipi di array:

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

o se vuoi i valori interi:

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

Ovviamente puoi iterare quegli array trasmessi :)


7

Che ne dici di un elenco di dizionari?

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

e ovviamente puoi cambiare il tipo di valore del dizionario in qualunque siano i tuoi valori enum.


Penso che questa sarebbe la strada da percorrere, ma sfortunatamente l'enumerazione si trova in un'area del codice su cui non ho alcun controllo!
TK.

1
L'unica soluzione che ho trovato che ottiene i valori di enumerazione interi effettivi!
SharpC

5

Un'altra soluzione, con interessanti possibilità:

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

Eccone un altro. Avevamo bisogno di fornire nomi descrittivi per i nostri EnumValues. Abbiamo usato System.ComponentModel.DescriptionAttribute per mostrare un valore stringa personalizzato per ogni valore enum.

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 uso

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



    static void Main(string[] args)
    {

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

Questo finirà per restituire "Something 1", "Something 2"


1
Buono solo se le descrizioni sono statiche ... se le tue descrizioni devono cambiare in base alle istanze, questo approccio non funzionerà.
Llyle

3

Che ne dici di usare un ciclo foreach, forse potresti lavorarci?

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

qualcosa del genere forse?


Ne ho già parlato ... ma ho bisogno di accedere a nomi e valori in "sincronizzazione" ... diciamo che i nomi [2] sono associati a valori [2] e non sono sicuro di come ottenerlo in un ciclo foreach!
TK.

Ho aggiunto un esempio: vedi se aiuta.
TWith2Sugars

3

Vecchia domanda, ma un approccio leggermente più pulito usando LINQ .Cast<>()

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

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

2

Array ha un metodo GetValue (Int32) che puoi usare per recuperare il valore in corrispondenza di un indice specificato.

Array.GetValue


2

Puoi semplificarlo usando le stringhe di formato. Uso il seguente frammento nei messaggi di utilizzo:

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

L'identificatore di formato D formatta il valore enum come decimale. C'è anche un identificatore X che fornisce un output esadecimale.

L'identificatore G formatta un'enumerazione come stringa. Se l'attributo Flags viene applicato all'enumerazione, vengono supportati anche i valori combinati. C'è uno specificatore F che agisce come se Flags fosse sempre presente.

Vedere Enum.Format ().


2

Nei risultati Enum.GetValues, il cast a int produce il valore numerico. L'utilizzo di ToString () produce il nome descrittivo. Non sono necessarie altre chiamate a 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
 */

0

Ecco un modo semplice per scorrere il tuo oggetto Enum personalizzato

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

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

Next

1
Penso che OP abbia chiesto C #.
jm.

0

Domanda antica, ma la risposta di 3Dave ha fornito l'approccio più semplice. Avevo bisogno di un piccolo metodo di supporto per generare uno script Sql per decodificare un valore enum nel database per il debug. Ha funzionato alla grande:

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

Ce l'ho in un metodo statico, quindi l'utilizzo è:

var cheater = MyStaticClass.EnumToCheater<MyEnum>()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.