web-dev-qa-db-fra.com

Comment énumérer une énumération en C #?

Comment pouvez-vous é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 donne l'erreur de compilation suivante:

'Suit' est un 'type' mais est utilisé comme une 'variable'

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

3546
Ian Boyd
foreach (Suit suit in (Suit[]) Enum.GetValues(typeof(Suit)))
{
}

Remarque : Le transtypage en (Suit[]) n'est pas strictement nécessaire, mais accélère le code de 0,5 ns.

4363
jop

Il me semble que vous voulez vraiment imprimer les noms de chaque énumération 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);
    }
}

En passant, incrémenter la valeur n'est pas un bon moyen d'énumérer les valeurs d'une énumération. Vous devriez le faire à la place.

Je voudrais utiliser 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());
    }
}
652
Haacked

J'ai fait quelques extensions pour une utilisation facile d'énum, ​​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 le FlagsAttribute

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

Certaines versions du framework .NET ne prennent pas en charge Enum.GetValues. Voici une bonne solution de contournement de Ideas 2.0: Enum.GetValues ​​in 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 impliquant réflexion , vous devez vous assurer qu'il ne s'exécute qu'une seule fois et que les résultats sont mis en cache.

170
Ekevoo

Pourquoi personne n'utilise Cast<T>?

var suits = Enum.GetValues(typeof(Suit)).Cast<Suit>();

Là vous allez IEnumerable<Suit>.

104
sircodesalot

Je pense que cela est plus efficace que d’autres suggestions car GetValues() n’est pas appelé à chaque fois que vous avez une boucle. C'est aussi plus concis. Et vous obtenez une erreur de compilation et non 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]);
        }
    }
}
93
James

Vous n'obtiendrez pas Enum.GetValues() dans Silverlight.

Blog original posté par Einar Ingebrigtsen :

public class EnumHelper
{
    public static T[] GetValues<T>()
    {
        Type enumType = typeof(T);

        if (!enumType.IsEnum)
        {
            throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");
        }

        List<T> values = new List<T>();

        var fields = from field in enumType.GetFields()
                     where field.IsLiteral
                     select field;

        foreach (FieldInfo field in fields)
        {
            object value = field.GetValue(enumType);
            values.Add((T)value);
        }

        return values.ToArray();
    }

    public static object[] GetValues(Type enumType)
    {
        if (!enumType.IsEnum)
        {
            throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");
        }

        List<object> values = new List<object>();

        var fields = from field in enumType.GetFields()
                     where field.IsLiteral
                     select field;

        foreach (FieldInfo field in fields)
        {
            object value = field.GetValue(enumType);
            values.Add(value);
        }

        return values.ToArray();
    }
}
74
Aubrey Taylor

Juste pour ajouter ma solution, qui fonctionne dans un cadre compact (3.5) et supporte la vérification de type au moment de la compilation:

public static List<T> GetEnumValues<T>() where T : new() {
    T valueType = new T();
    return typeof(T).GetFields()
        .Select(fieldInfo => (T)fieldInfo.GetValue(valueType))
        .Distinct()
        .ToList();
}

public static List<String> GetEnumNames<T>() {
    return typeof (T).GetFields()
        .Select(info => info.Name)
        .Distinct()
        .ToList();
}

- Si quelqu'un sait comment se débarrasser de la T valueType = new T(), je serais heureux de voir une solution.

Un appel ressemblerait à ceci:

List<MyEnum> result = Utils.GetEnumValues<MyEnum>();
56
Mallox

Je pense que vous pouvez utiliser

Enum.GetNames(Suit)
51
Tom Carr
public void PrintAllSuits()
{
    foreach(string suit in Enum.GetNames(typeof(Suits)))
    {
        Console.WriteLine(suit);
    }
}
49
Joshua Drake
foreach (Suit suit in Enum.GetValues(typeof(Suit))) { }

J'ai entendu de vagues rumeurs selon lesquelles c'est terriblement lent. Quelqu'un sait? - Orion Edwards 15 Oct. 08 à 1:31 7

Je pense que la mise en cache du tableau l’accélérerait considérablement. Il semble que vous obteniez un nouveau tableau (par réflexion) à chaque fois. Plutôt:

Array enums = Enum.GetValues(typeof(Suit));
foreach (Suit suitEnum in enums) 
{
    DoSomething(suitEnum);
}

C'est au moins un peu plus rapide, ja?

48
Limited Atonement

Trois façons:

1. Enum.GetValues(type) //since .NET 1.1, not in silverlight or compact framewok
2. type.GetEnumValues() //only on .NET 4 and above
3. type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)) //works everywhere

Je ne sais pas pourquoi GetEnumValues a été introduit sur l'instance de type, ce n'est pas très lisible du tout pour moi.


Avoir une classe d'assistance comme Enum<T> est ce qui est le plus lisible et le plus mémorable pour moi:

public static class Enum<T> where T : struct, IComparable, IFormattable, IConvertible
{
    public static IEnumerable<T> GetValues()
    {
        return (T[])Enum.GetValues(typeof(T));
    }

    public static IEnumerable<string> GetNames()
    {
        return Enum.GetNames(typeof(T));
    }
}

Maintenant tu appelles:

Enum<Suit>.GetValues();
//or
Enum.GetValues(typeof(Suit)); //pretty consistent style

On peut également utiliser une sorte de cache si les performances comptent, mais je ne m'attends pas à ce que ce soit un problème.

public static class Enum<T> where T : struct, IComparable, IFormattable, IConvertible
{
    //lazily loaded
    static T[] values;
    static string[] names;

    public static IEnumerable<T> GetValues()
    {
        return values ?? (values = (T[])Enum.GetValues(typeof(T)));
    }

    public static IEnumerable<string> GetNames()
    {
        return names ?? (names = Enum.GetNames(typeof(T)));
    }
}
27
nawfal

Qu'est-ce que je vais jeter mes deux pence dedans, simplement en combinant les réponses du haut je traverse ensemble une extension très simple

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 T value) where T : Enum
    {
        return (T[])Enum.GetValues(typeof (T));
    }
}

Propre simple et par commentaire de Jeppe-Stig-Nielsen rapide.

26
Darkside

J'utilise ToString () puis divise et analyse le tableau de crachat en drapeaux.

[Flags]
public enum ABC {
   a = 1,
   b = 2,
   c = 4
};

public IEnumerable<ABC> Getselected (ABC flags)
{
   var values = flags.ToString().Split(',');
   var enums = values.Select(x => (ABC)Enum.Parse(typeof(ABC), x.Trim()));
   return enums;
}

ABC temp= ABC.a | ABC.b;
var list = getSelected (temp);
foreach (var item in list)
{
   Console.WriteLine(item.ToString() + " ID=" + (int)item);
}
22
Mickey Perlstein

Il y a deux façons d'itérer un Enum:

1. var values =  Enum.GetValues(typeof(myenum))
2. var values =  Enum.GetNames(typeof(myenum))

Le premier vous donnera des valeurs sous forme sur un tableau de object, et le second vous donnera des valeurs sous forme de tableau de String.

Utilisez-le dans la boucle foreach comme ci-dessous:

foreach(var value in values)
{
    //Do operations here
}
21
Kylo Ren

Si vous avez besoin de vérifier la vitesse et le type lors de la compilation et de l'exécution, cette méthode d'assistance est préférable à l'utilisation de LINQ pour transtyper chaque élément:

public static T[] GetEnumValues<T>() where T : struct, IComparable, IFormattable, IConvertible
{
    if (typeof(T).BaseType != typeof(Enum))
    {
        throw new ArgumentException(string.Format("{0} is not of type System.Enum", typeof(T)));
    }
    return Enum.GetValues(typeof(T)) as T[];
}

Et vous pouvez l'utiliser comme ci-dessous:

static readonly YourEnum[] _values = GetEnumValues<YourEnum>();

Bien sûr, vous pouvez retourner IEnumerable<T>, mais cela ne vous rapporte rien.

16
dmihailescu

Je ne crois pas que cela soit meilleur, ni même bon, simplement énoncer une autre solution.

Si les valeurs enum vont strictement de 0 à n - 1, une alternative générique:

public void EnumerateEnum<T>()
{
    int length = Enum.GetValues(typeof(T)).Length;
    for (var i = 0; i < length; i++)
    {
        var @enum = (T)(object)i;
    }
}

Si les valeurs enum sont contiguës et que vous pouvez fournir le premier et le dernier élément de l'énum, ​​alors:

public void EnumerateEnum()
{
    for (var i = Suit.Spade; i <= Suit.Diamond; i++)
    {
        var @enum = i;
    }
}

mais ce n'est pas strictement énumérant, juste en boucle. La deuxième méthode est beaucoup plus rapide que toute autre approche cependant ...

16
nawfal

voici un exemple de travail de création d'options de sélection pour une DDL

var resman = ViewModelResources.TimeFrame.ResourceManager;

ViewBag.TimeFrames = from MapOverlayTimeFrames timeFrame 
      in Enum.GetValues(typeof(MapOverlayTimeFrames))
      select new SelectListItem
      {
         Value = timeFrame.ToString(),
         Text = resman.GetString(timeFrame.ToString()) ?? timeFrame.ToString()
      };
13
jhilden
foreach (Suit suit in Enum.GetValues(typeof(Suit)))
{
}

(La réponse acceptée actuellement a un casting que je ne pense pas nécessaire (bien que je puisse me tromper).)

10
matt burns

Cette question apparaît au chapitre 10 de " C # étape par étape 201 "

L'auteur utilise une double boucle for pour parcourir une paire d'énumérateurs (afin de créer un jeu de cartes complet):

class Pack
{
    public const int NumSuits = 4;
    public const int CardsPerSuit = 13;
    private PlayingCard[,] cardPack;

    public Pack()
    {
        this.cardPack = new PlayingCard[NumSuits, CardsPerSuit];
        for (Suit suit = Suit.Clubs; suit <= Suit.Spades; suit++)
        {
            for (Value value = Value.Two; value <= Value.Ace; value++)
            {
                cardPack[(int)suit, (int)value] = new PlayingCard(suit, value);
            }
        }
    }
}

Dans ce cas, Suit et Value sont les deux énumérations:

enum Suit { Clubs, Diamonds, Hearts, Spades }
enum Value { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace}

et PlayingCard est un objet de carte avec un Suit et un Value définis:

class PlayingCard
{
    private readonly Suit suit;
    private readonly Value value;

    public PlayingCard(Suit s, Value v)
    {
        this.suit = s;
        this.value = v;
    }
}
10
Ross Gatih

Je sais que c'est un peu brouillon, mais si vous êtes fan de one-liners, en voici un:

((Suit[])Enum.GetValues(typeof(Suit))).ToList().ForEach(i => DoSomething(i));
9
anar khalilov

Que se passe-t-il si vous savez que le type sera un enum, mais que vous ne connaissez pas le type exact au moment de la compilation?

public class EnumHelper
{
    public static IEnumerable<T> GetValues<T>()
    {
        return Enum.GetValues(typeof(T)).Cast<T>();
    }

    public static IEnumerable getListOfEnum(Type type)
    {
        MethodInfo getValuesMethod = typeof(EnumHelper).GetMethod("GetValues").MakeGenericMethod(type);
        return (IEnumerable)getValuesMethod.Invoke(null, null);
    }
}

La méthode getListOfEnum utilise la réflexion pour prendre tout type d’énumération et renvoie un IEnumerable de toutes les valeurs d’énumération.

Usage:

Type myType = someEnumValue.GetType();

IEnumerable resultEnumerable = getListOfEnum(myType);

foreach (var item in resultEnumerable)
{
    Console.WriteLine(String.Format("Item: {0} Value: {1}",item.ToString(),(int)item));
}
8
Slappywag

Un moyen simple et générique de convertir une énumération en quelque chose que vous pouvez interagir:

public static Dictionary<int, string> ToList<T>() where T : struct
{
   return ((IEnumerable<T>)Enum
       .GetValues(typeof(T)))
       .ToDictionary(
           item => Convert.ToInt32(item),
           item => item.ToString());
}

Puis:

var enums = EnumHelper.ToList<MyEnum>();
8
Gabriel

Ajoutez la méthode public static IEnumerable<T> GetValues<T>() à votre classe, comme

public static IEnumerable<T> GetValues<T>()
{
    return Enum.GetValues(typeof(T)).Cast<T>();
}

appelle et passe ton enum, tu peux maintenant le parcourir en utilisant foreach

 public static void EnumerateAllSuitsDemoMethod()
 {
     // custom method
     var foos = GetValues<Suit>(); 
     foreach (var foo in foos)
     {
         // Do something
     }
 }
5
MUT

Les types enum sont appelés "types d'énumération" non pas parce qu'ils sont des conteneurs qui "énumèrent" des valeurs (ce qu'ils ne sont pas), mais parce qu'ils sont définis par enumerating les valeurs possibles pour une variable de ce type.

(En fait, c'est un peu plus compliqué que cela - les types enum sont considérés comme ayant un type entier "sous-jacent", ce qui signifie que chaque valeur enum correspond à une valeur entière (ceci est généralement implicite, mais peut être spécifié manuellement). C # a été conçu de manière à pouvoir insérer n'importe quel entier de ce type dans la variable enum, même s'il ne s'agit pas d'une valeur "nommée".

La méthode System.Enum.GetNames peut être utilisée pour extraire un tableau de chaînes contenant le nom des valeurs enum, comme son nom l'indique.

EDIT: aurait dû suggérer plutôt la méthode System.Enum.GetValues . Oops.

1
Emily Chen

Vous pouvez également vous connecter directement aux membres statiques publics de l'énum en utilisant la réflexion:

typeof(Suit).GetMembers(BindingFlags.Public | BindingFlags.Static)
    .ToList().ForEach(x => DoSomething(x.Name));
0
Termininja