Comment puis-je énumérer un enum en C#?
Comment Pouvez-vous énumérer un enum
dans C#?
E. G. le code suivant Ne se 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:
de "Costume" est un "type" mais est utilisée comme une "variable"
il échoue sur le mot-clé Suit
, le second.
26 réponses
foreach (Suit suit in (Suit[]) Enum.GetValues(typeof(Suit)))
{
}
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);
}
}
Par ailleurs, l'incrémentation de la valeur n'est pas une bonne façon d'énumérer les valeurs d'une énumération. Vous devez faire cela à la place.
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());
}
}
j'ai fait quelques extensions pour l'utilisation facile d'enum, 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'enum lui-même doit être décoré avec le FlagsAttribute
[Flags]
public enum EnumExample
{
ValueA = 1,
ValueB = 2,
ValueC = 4,
ValueD = 8,
Combi = ValueA | ValueB
}
certaines versions du .net framework ne prennent pas en charge Enum.GetValues
. Voici une bonne solution de contournement de idées 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 qui implique réflexion , vous devez prendre des mesures pour vous assurer qu'il ne s'exécute qu'une seule fois et que les résultats sont mis en cache.
je pense que c'est plus efficace que d'autres suggestions parce que GetValues()
n'est pas appelé chaque fois que vous avez une boucle. Il est également plus concis. Et vous obtenez une erreur de compilation 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]);
}
}
}
pourquoi personne n'utilise Cast<T>
?
var suits = Enum.GetValues(typeof(Suit)).Cast<Suit>();
et voilà IEnumerable<Suit>
.
vous n'aurez pas Enum.GetValues()
à Silverlight.
billet original du Blog 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();
}
}
juste pour ajouter ma solution, qui fonctionne dans le cadre compact (3.5) et soutient le contrôle de type à l'Heure de 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 du T valueType = new T()
, je serais heureux de voir une solution.
un appel ressemblerait à ceci:
List<MyEnum> result = Utils.GetEnumValues<MyEnum>();
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 que c'est terifically slow. Tout le monde sait? – Orion Edwards Oct 15 ' 08 à 1: 31 7
je pense que la mise en cache du tableau l'accélérerait considérablement. On dirait que vous obtenez 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?
trois voies:
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, il n'est pas très lisible du tout pour moi.
avoir une classe d'aide comme Enum<T>
est ce qui est le plus lisible et 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 vous appelez:
Enum<Suit>.GetValues();
//or
Enum.GetValues(typeof(Suit)); //pretty consistent style
on peut aussi utiliser une sorte de cache si la performance importe, mais je ne vous attendez pas à être 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)));
}
}
Ce que l'enfer je vais jeter mes deux pence, juste en combinant les réponses les plus fréquentes que je travers 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 et simple par @Jeppe-Stig-Nielsen s commentaire rapide.
j'utilise ToString() puis je divise et parse le tableau spit 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);
}
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))
La première sera de vous donner les valeurs en forme sur un tableau de object
, et le second vous donnera des valeurs sous forme de tableau de String
.
utilisez-le dans foreach
boucle comme ci-dessous:
foreach(var value in values)
{
//Do operations here
}
Je ne suis pas d'avis que c'est mieux, ou même bon, de simplement énoncer une autre solution.
si les valeurs enum varient 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'enum, alors:
public void EnumerateEnum()
{
for (var i = Suit.Spade; i <= Suit.Diamond; i++)
{
var @enum = i;
}
}
mais ce n'est pas une énumération stricte, juste une boucle. La deuxième méthode est beaucoup plus rapide que toute autre approche bien...
si vous avez besoin d'un contrôle de vitesse et de type au temps de construction et d'exécution, cette méthode d'aide est meilleure que L'utilisation de LINQ pour mouler 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 que vous achète rien ici.
voici un exemple pratique de création d'options select 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()
};
foreach (Suit suit in Enum.GetValues(typeof(Suit)))
{
}
(Le courant a accepté de répondre a un casting que je ne pense pas que est nécessaire (bien que je puisse me tromper).)
cette question apparaît au chapitre 10 de " C# étape par étape 2013 "
l'auteur utilise une double boucle pour itérer à travers une paire d'enquêteurs (pour créer un jeu complet de cartes):
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 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 défini Suit
et Value
:
class PlayingCard
{
private readonly Suit suit;
private readonly Value value;
public PlayingCard(Suit s, Value v)
{
this.suit = s;
this.value = v;
}
}
je sais que c'est un peu bordélique, mais si vous êtes fan des monocouches, en voici un:
((Suit[])Enum.GetValues(typeof(Suit))).ToList().ForEach(i => DoSomething(i));
une façon simple et générique de convertir un enum 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 ensuite:
var enums = EnumHelper.ToList<MyEnum>();
Que faire si vous savez que le type sera un enum
, mais que vous ne savez pas quel est 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 d'enum et renvoie un IEnumerable
de toutes les valeurs d'enum.
Utilisation:
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));
}
ajouter 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>();
}
appeler et passer votre enum, maintenant vous pouvez itérer à travers elle en utilisant foreach
public static void EnumerateAllSuitsDemoMethod()
{
// custom method
var foos = GetValues<Suit>();
foreach (var foo in foos)
{
// Do something
}
}
vous pouvez aussi lier directement au public les membres statiques de l'enum en utilisant la réflexion:
typeof(Suit).GetMembers(BindingFlags.Public | BindingFlags.Static)
.ToList().ForEach(x => DoSomething(x.Name));
enum
les types 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 énumérer 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 (ce qui est généralement implicite, mais peut être spécifié manuellement). C# a été conçu de manière à ce que vous puissiez insérer n'importe quel "entier 151930920" de ce type dans la variable enum, même si ce n'est pas une valeur "nommée".)
Le Système .Enum.La méthode GetNames peut être utilisée pour récupérer un tableau de chaînes qui sont les noms des valeurs enum, comme leur nom l'indique.
modifier: aurait dû suggérer le système .Enum.GetValues méthode plutôt. Oops.