.net d'une - Comment énumérer une énumération en C#?




taille liste (22)

Comment pouvez-vous énumérer une 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.


Answers

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

Vous ne savez pas pourquoi GetEnumValues été introduit sur une 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)));
    }
}

Voici un exemple de travail de création d'options de sélection pour un 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()
      };

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 convertir 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.


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

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

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?


Ajoutez une 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
     }
 }

Juste pour ajouter ma solution, qui fonctionne dans un cadre compact (3.5) et prend en charge 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 T valueType = new T() , je serais heureux de voir une solution.

Un appel ressemblerait à ceci:

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

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

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


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

J'utilise ToString (), puis divise et analyse le tableau de sélection en indicateurs.

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

Pourquoi personne n'utilise Cast<T> ?

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

Là vous allez IEnumerable<Suit> .


enum 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 en énumérant 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 la méthode System.Enum.GetValues place. Oops.


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

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

Il existe deux manières de parcourir 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 d' 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
}

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

Et alors:

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

Que se passe-t-il si vous savez que le type sera une 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 n'importe quel type enum et renvoie un IEnumerable de toutes les valeurs enum.

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

Certaines versions du framework .NET ne prennent pas en charge Enum.GetValues . Voici une bonne solution à partir d' Ideas 2.0: Enum.GetValues ​​in Compact Framework :

public List<Enum> GetValues(Enum enumeration)
{
   List<Enum> enumerations = new List<Enum>();
   foreach (FieldInfo fieldInfo in enumeration.GetType().GetFields(
         BindingFlags.Static | BindingFlags.Public))
   {
      enumerations.Add((Enum)fieldInfo.GetValue(enumeration));
   }
   return enumerations;
}

Comme pour tout code impliquant une reflection , vous devez vous assurer qu'il ne s'exécute qu'une seule fois et que les résultats sont mis en cache.


Cette question apparaît dans le chapitre 10 de " C # Step by Step 2013 "

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

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 ...


Qu'en est-il de?

public enum MyEnum {
    FIRST,
    SECOND,
    THIRD;

    public static Optional<MyEnum> fromString(String value){
        try{
            return Optional.of(MyEnum.valueOf(value));
        }catch(Exception e){
            return Optional.empty();
        }
    }
}




c# .net enums enumeration