4287 votes

Comment énumérer une énumération

Comment peut-on énumérer un enum en C# ?

Par exemple, le code suivant ne compile pas :

public enum Suit
{
    Spades,
    Hearts,
    Clubs,
    Diamonds
}

public void EnumerateAllSuitsDemoMethod()
{
    foreach (Suit suit in Suit)
    {
        DoSomething(suit);
    }
}

Et cela donne l'erreur de compilation suivante :

Suit" est un "type" mais est utilisé comme une "variable".

Il échoue sur le Suit mot-clé, le deuxième.

20 votes

4 votes

Vous pouvez consulter les tenants et aboutissants des enums de C# qui traite de ce sujet ainsi que d'autres informations utiles sur les enum.

5186voto

jop Points 31978
foreach (Suit suit in (Suit[]) Enum.GetValues(typeof(Suit)))
{
}

Nota : Le casting pour (Suit[]) n'est pas strictement nécessaire, mais cela rend le code 0.5 ns plus rapide .

110 votes

Cela ne fonctionne pas si vous avez des valeurs en double dans la liste des énumérateurs.

2 votes

@Jessy si vous avez besoin de tous les noms (y compris ceux avec des valeurs dupliquées), essayez peut-être Enum.GetNames en conjonction avec Enum.Parse. Cela va être un peu lent cependant, je recommande de le faire une fois pendant l'initialisation (ou la première fois qu'il est nécessaire) et de mettre en cache les résultats dans un tableau.

11 votes

Je veux juste signaler que, malheureusement, cela ne fonctionnera pas en silverlight, puisque la bibliothèque silverlight ne comprend pas les éléments suivants enum.GetValues . Vous devez utiliser la réflexion dans ce cas.

810voto

Haacked Points 31070

Il me semble que vous voulez vraiment imprimer les noms de chaque enum, plutôt que les valeurs. Dans ce cas Enum.GetNames() semble être la bonne approche.

public enum Suits
{
    Spades,
    Hearts,
    Clubs,
    Diamonds,
    NumSuits
}

public void PrintAllSuits()
{
    foreach (string name in Enum.GetNames(typeof(Suits)))
    {
        System.Console.WriteLine(name);
    }
}

Au fait, l'incrémentation de la valeur n'est pas une bonne façon d'énumérer les valeurs d'une énumération. Vous devriez plutôt faire ceci.

J'utiliserais Enum.GetValues(typeof(Suit)) à la place.

public enum Suits
{
    Spades,
    Hearts,
    Clubs,
    Diamonds,
    NumSuits
}

public void PrintAllSuits()
{
    foreach (var suit in Enum.GetValues(typeof(Suits)))
    {
        System.Console.WriteLine(suit.ToString());
    }
}

3 votes

Syntaxe VB ici : lien

1 votes

J'ai pris votre version avec quelques modifications de mon côté : Enum.GetValues(typeof(Suits)).OfType<Suits>().ToArray() . Dans ce cas, je peux itérer un tableau de Suits des éléments d'énumération, pas des chaînes de caractères.

2 votes

@Barabas pourquoi ne pas simplement faire Suits suit in Enum.GetValues(typeof(Suits)) ?

384voto

bob Points 3408

J'ai fait quelques extensions pour faciliter l'utilisation des enums. Peut-être que quelqu'un peut l'utiliser...

public static class EnumExtensions
{
    /// <summary>
    /// Gets all items for an enum value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public static IEnumerable<T> GetAllItems<T>(this Enum value)
    {
        foreach (object item in Enum.GetValues(typeof(T)))
        {
            yield return (T)item;
        }
    }

    /// <summary>
    /// Gets all items for an enum type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    public static IEnumerable<T> GetAllItems<T>() where T : struct
    {
        foreach (object item in Enum.GetValues(typeof(T)))
        {
            yield return (T)item;
        }
    }

    /// <summary>
    /// Gets all combined items from an enum value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <returns></returns>
    /// <example>
    /// Displays ValueA and ValueB.
    /// <code>
    /// EnumExample dummy = EnumExample.Combi;
    /// foreach (var item in dummy.GetAllSelectedItems<EnumExample>())
    /// {
    ///    Console.WriteLine(item);
    /// }
    /// </code>
    /// </example>
    public static IEnumerable<T> GetAllSelectedItems<T>(this Enum value)
    {
        int valueAsInt = Convert.ToInt32(value, CultureInfo.InvariantCulture);

        foreach (object item in Enum.GetValues(typeof(T)))
        {
            int itemAsInt = Convert.ToInt32(item, CultureInfo.InvariantCulture);

            if (itemAsInt == (valueAsInt & itemAsInt))
            {
                yield return (T)item;
            }
        }
    }

    /// <summary>
    /// Determines whether the enum value contains a specific value.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="request">The request.</param>
    /// <returns>
    ///     <c>true</c> if value contains the specified value; otherwise, <c>false</c>.
    /// </returns>
    /// <example>
    /// <code>
    /// EnumExample dummy = EnumExample.Combi;
    /// if (dummy.Contains<EnumExample>(EnumExample.ValueA))
    /// {
    ///     Console.WriteLine("dummy contains EnumExample.ValueA");
    /// }
    /// </code>
    /// </example>
    public static bool Contains<T>(this Enum value, T request)
    {
        int valueAsInt = Convert.ToInt32(value, CultureInfo.InvariantCulture);
        int requestAsInt = Convert.ToInt32(request, CultureInfo.InvariantCulture);

        if (requestAsInt == (valueAsInt & requestAsInt))
        {
            return true;
        }

        return false;
    }
}

L'énumération elle-même doit être décorée avec l'attribut Attribut de drapeaux :

[Flags]
public enum EnumExample
{
    ValueA = 1,
    ValueB = 2,
    ValueC = 4,
    ValueD = 8,
    Combi = ValueA | ValueB
}

19 votes

Une seule ligne pour la première méthode d'extension ; ce n'est pas plus paresseux. return Enum.GetValues(typeof(T)).Cast<T>() ;

2 votes

Vous pouvez également utiliser OfType : Enum.GetValues(typeof(T)).OfType<T>(). C'est dommage qu'il n'y ait pas une version générique de GetValues<T>(), ce serait encore plus efficace.

3 votes

Peut-être que quelqu'un pourrait montrer comment utiliser ces extensions ? Le compilateur ne montre pas les méthodes d'extension sur l'enum EnumExample.

199voto

Ekevoo Points 906

Certaines versions de .NET framework ne prennent pas en charge Enum.GetValues . Voici une bonne solution de contournement de Idées 2.0 : Enum.GetValues dans Compact Framework :

public Enum[] GetValues(Enum enumeration)
{
    FieldInfo[] fields = enumeration.GetType().GetFields(BindingFlags.Static | BindingFlags.Public);
    Enum[] enumerations = new Enum[fields.Length];

    for (var i = 0; i < fields.Length; i++)
        enumerations[i] = (Enum) fields[i].GetValue(enumeration);

    return enumerations;
}

Comme pour tout code qui implique réflexion vous devez prendre des mesures pour vous assurer qu'il n'est exécuté qu'une seule fois et que les résultats sont mis en cache.

19 votes

Pourquoi ne pas utiliser le mot-clé yield ici au lieu d'instancier une liste ?

1 votes

Ou plus court : return type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)).Cast<Enum>();

10 votes

@nawfal : Linq n'est pas disponible dans .Net CF 2.0.

111voto

James Points 507

Je pense que cette solution est plus efficace que les autres suggestions car GetValues() n'est pas appelé à chaque fois que vous avez une boucle. Il est également plus concis. Et vous obtenez une erreur de compilation, et non pas une exception d'exécution si Suit n'est pas un enum .

EnumLoop<Suit>.ForEach((suit) => {
    DoSomethingWith(suit);
});

EnumLoop a cette définition complètement générique :

class EnumLoop<Key> where Key : struct, IConvertible {
    static readonly Key[] arr = (Key[])Enum.GetValues(typeof(Key));
    static internal void ForEach(Action<Key> act) {
        for (int i = 0; i < arr.Length; i++) {
            act(arr[i]);
        }
    }
}

8 votes

Attention à l'utilisation de génériques comme ça. Si vous essayez d'utiliser EnumLoop avec un type qui n'est pas un enum, la compilation sera bonne, mais une exception sera levée à l'exécution.

8 votes

Merci svick. Les exceptions à l'exécution se produiront effectivement avec les autres réponses de cette page... sauf celle-ci car j'ai ajouté "where Key : struct, IConvertible" pour que vous obteniez une erreur à la compilation dans la plupart des cas.

3 votes

Non, GetValues() est appelé une seule fois dans le foreach.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X