C # Itérer dans une énumération? (Indexation d'un System.Array)

113

J'ai le code suivant:

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

Cependant, je ne peux pas indexer les valeurs. Existe-t-il un moyen plus simple de le faire?

Ou ai-je manqué quelque chose d'entièrement!

TK.
la source

Réponses:

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

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

Ou, vous pouvez convertir le System.Array renvoyé:

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

Mais pouvez-vous être sûr que GetValues ​​renvoie les valeurs dans le même ordre que GetNames renvoie les noms?

Frederik Gheysels
la source
3
"Mais, pouvez-vous être sûr que GetValues ​​renvoie les valeurs dans le même ordre que GetNames renvoie les noms?" - C'est un très bon point et quelque chose que je n'ai pas encore abordé! Je pense que votre première solution fournirait probablement un moyen de faire correspondre les valeurs et les chaînes de manière fiable
TK.
Bonjour, j'ai déjà vu la mention de cette suspicion de "non-concordance d'index" se produisant lors de cette opération; cependant, je n'ai pas encore découvert si c'est vraiment un problème ou non? Existe-t-il des cas définitifs dans lesquels cette hypothèse pourrait mal tourner? THX!
Funka
Vous souhaiterez probablement convertir le second "val" en un entier, si vous souhaitez résoudre les problèmes de non-concordance de valeurs, comme Enum.GetName(typeof(MyEnum), val), (int)val)dans lequel la sortie fournit le nom et le numéro de l'énumération.
Greg
GetValues ​​et GetNames retournent dans le même ordre, à savoir: "Les éléments du tableau de valeurs de retour sont triés par les valeurs binaires des constantes énumérées (c'est-à-dire par leur grandeur non signée)."
Russell Borogove
Je crois que vous pouvez également utiliser LINQ directement en appelant Cast<T>le résultat:Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>()...
jocull
33

Vous devez transtyper le tableau - le tableau retourné est en fait du type demandé, c'est myEnum[]-à- dire si vous demandez typeof(myEnum):

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

Puis values[0]etc

Marc Gravell
la source
9

Vous pouvez convertir ce tableau en différents types de tableaux:

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

ou si vous voulez les valeurs entières:

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

Vous pouvez bien sûr itérer ces tableaux coulés :)

Arcturus
la source
7

Que diriez-vous d'une liste de dictionnaires?

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

et bien sûr, vous pouvez changer le type de valeur du dictionnaire en quelles que soient vos valeurs d'énumération.

mrtaikandi
la source
Je pense que ce serait la voie à suivre, mais malheureusement, l'énumération est dans une zone de code sur laquelle je n'ai aucun contrôle!
TK.
1
La seule solution que j'ai trouvée qui obtient les valeurs réelles d'énumération entière!
SharpC
5

Une autre solution, avec des possibilités intéressantes:

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
la source
4

En voici une autre. Nous avions besoin de fournir des noms conviviaux pour nos EnumValues. Nous avons utilisé le System.ComponentModel.DescriptionAttribute pour afficher une valeur de chaîne personnalisée pour chaque valeur d'énumération.

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

Utilisé

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



    static void Main(string[] args)
    {

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

Cela finira par renvoyer "Quelque chose 1", "Quelque chose 2"

Château de Kevin
la source
1
Seulement bon si les descriptions sont statiques ... si vos descriptions doivent changer en fonction d'une instance, cette approche ne fonctionnera pas.
Llyle
3

Et si vous utilisiez une boucle foreach, vous pourriez peut-être travailler avec ça?

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

quelque chose comme ça peut-être?

TWith2Sucres
la source
J'en ai trop ... mais je dois avoir accès aux noms et aux valeurs en "synchro" ... disons que les noms [2] sont associés à des valeurs [2] et je ne sais pas comment y parvenir en une boucle foreach!
TK.
J'ai ajouté un exemple - voyez si cela aide.
TWith2Sugars
3

Ancienne question, mais une approche légèrement plus claire utilisant LINQ .Cast<>()

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

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

Array a une méthode GetValue (Int32) que vous pouvez utiliser pour récupérer la valeur à un index spécifié.

Array.GetValue

Papier bulle
la source
2

Vous pouvez simplifier cela en utilisant des chaînes de format. J'utilise l'extrait suivant dans les messages d'utilisation:

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

Le spécificateur de format D met en forme la valeur d'énumération sous forme décimale. Il existe également un spécificateur X qui donne une sortie hexadécimale.

Le spécificateur G formate une énumération sous forme de chaîne. Si l'attribut Flags est appliqué à l'énumération, les valeurs combinées sont également prises en charge. Il existe un spécificateur F qui agit comme si Flags était toujours présent.

Voir Enum.Format ().

Frank Szczerba
la source
2

Dans les résultats Enum.GetValues, la conversion en int produit la valeur numérique. L'utilisation de ToString () produit le nom convivial. Aucun autre appel à Enum.GetName n'est nécessaire.

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
la source
0

Voici un moyen simple de parcourir votre objet Enum personnalisé

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

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

Next
Chev
la source
1
Je pense que OP a demandé C #.
jm.
0

Question ancienne, mais la réponse de 3Dave a fourni l'approche la plus simple. J'avais besoin d'une petite méthode d'aide pour générer un script Sql pour décoder une valeur enum dans la base de données pour le débogage. Cela a très bien fonctionné:

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

Je l'ai dans une méthode statique, donc l'utilisation est:

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