c# - que - imprimir enum en c
¿Cómo enumero una enumeración en C#? (26)
¿Cómo se puede enumerar una enum
en C #?
Por ejemplo, el siguiente código no se compila:
public enum Suit
{
Spades,
Hearts,
Clubs,
Diamonds
}
public void EnumerateAllSuitsDemoMethod()
{
foreach (Suit suit in Suit)
{
DoSomething(suit);
}
}
Y da el siguiente error de compilación:
''Traje'' es un ''tipo'' pero se usa como una ''variable''
Falla en la palabra clave Suit
, la segunda.
foreach (Suit suit in Enum.GetValues(typeof(Suit))) { }
He escuchado rumores vagos de que esto es terriblemente lento. ¿Nadie sabe? - Orion Edwards, 15 de octubre de 2008 a la 1:31 7
Creo que el almacenamiento en caché de la matriz lo aceleraría considerablemente. Parece que cada vez se obtiene una nueva matriz (a través de la reflexión). Más bien:
Array enums = Enum.GetValues(typeof(Suit));
foreach (Suit suitEnum in enums)
{
DoSomething(suitEnum);
}
Eso es al menos un poco más rápido, ja?
No tengo la opinión de que esto es mejor, o incluso bueno, simplemente declarando otra solución.
Si los valores de enumeración van estrictamente de 0 a n - 1, una alternativa genérica:
public void EnumerateEnum<T>()
{
int length = Enum.GetValues(typeof(T)).Length;
for (var i = 0; i < length; i++)
{
var @enum = (T)(object)i;
}
}
Si los valores de enumeración son contiguos y puede proporcionar el primer y último elemento de la enumeración, entonces:
public void EnumerateEnum()
{
for (var i = Suit.Spade; i <= Suit.Diamond; i++)
{
var @enum = i;
}
}
pero eso no es estrictamente enumerar, solo hacer un bucle. El segundo método es mucho más rápido que cualquier otro enfoque, aunque ...
¿Por qué nadie usa Cast<T>
?
var suits = Enum.GetValues(typeof(Suit)).Cast<Suit>();
Ahí tienes IEnumerable<Suit>
.
¿Qué sucede si sabe que el tipo será una enum
pero no sabe cuál es el tipo exacto en el momento de la compilación?
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);
}
}
El método getListOfEnum
utiliza la reflexión para tomar cualquier tipo de enumeración y devuelve un IEnumerable
de todos los valores de enumeración.
Uso:
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));
}
Agregue el método public static IEnumerable<T> GetValues<T>()
a su clase, como
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
llama y pasa tu enum, ahora puedes recorrerla usando foreach
public static void EnumerateAllSuitsDemoMethod()
{
// custom method
var foos = GetValues<Suit>();
foreach (var foo in foos)
{
// Do something
}
}
Algunas versiones de .NET framework no admiten Enum.GetValues
. Aquí hay una buena solución de Ideas 2.0: Enum.GetValues en 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;
}
Al igual que con cualquier código que implique reflection , debe tomar medidas para asegurarse de que se ejecute solo una vez y que los resultados se almacenen en caché.
Aquí hay un ejemplo práctico de cómo crear opciones de selección para 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()
};
Creo que esto es más eficiente que otras sugerencias porque GetValues()
no se llama cada vez que tiene un bucle. También es más conciso. Y obtienes un error en tiempo de compilación, no una excepción de tiempo de ejecución si Suit
no es una enum
.
EnumLoop<Suit>.ForEach((suit) => {
DoSomethingWith(suit);
});
EnumLoop
tiene esta definición completamente genérica:
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]);
}
}
}
Creo que puedes usar
Enum.GetNames(Suit)
En qué diablos voy a tirar mis dos peniques, simplemente combinando las mejores respuestas, obtuve una extensión muy 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));
}
}
Limpio simple y por el comentario de @ Jeppe-Stig-Nielsen rápido.
Esta pregunta aparece en el Capítulo 10 de " C # Step by Step 2013 "
El autor utiliza un doble for-loop para iterar a través de un par de enumeradores (para crear un mazo de cartas completo):
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);
}
}
}
}
En este caso, Suit
y Value
son ambas enumeraciones:
enum Suit { Clubs, Diamonds, Hearts, Spades }
enum Value { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace}
y PlayingCard
es un objeto de tarjeta con un Suit
y Value
definidos:
class PlayingCard
{
private readonly Suit suit;
private readonly Value value;
public PlayingCard(Suit s, Value v)
{
this.suit = s;
this.value = v;
}
}
Hay dos formas de iterar un Enum
:
1. var values = Enum.GetValues(typeof(myenum))
2. var values = Enum.GetNames(typeof(myenum))
El primero le dará valores en forma en una matriz de object
, y el segundo le dará valores en forma de matriz de String
.
Úsalo en el bucle foreach
como se muestra a continuación:
foreach(var value in values)
{
//Do operations here
}
Hice algunas extensiones para un fácil uso de enumeración, tal vez alguien pueda usarlo ...
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;
}
}
La enumeración en sí debe estar decorada con el FlagsAttribute
[Flags]
public enum EnumExample
{
ValueA = 1,
ValueB = 2,
ValueC = 4,
ValueD = 8,
Combi = ValueA | ValueB
}
Me parece que realmente desea imprimir los nombres de cada enumeración, en lugar de los valores. En cuyo caso, Enum.GetNames()
parece ser el enfoque correcto.
public enum Suits
{
Spades,
Hearts,
Clubs,
Diamonds,
NumSuits
}
public void PrintAllSuits()
{
foreach (string name in Enum.GetNames(typeof(Suits)))
{
System.Console.WriteLine(name);
}
}
Por cierto, aumentar el valor no es una buena manera de enumerar los valores de una enumeración. Deberías hacer esto en su lugar.
Yo usaría Enum.GetValues(typeof(Suit))
lugar.
public enum Suits
{
Spades,
Hearts,
Clubs,
Diamonds,
NumSuits
}
public void PrintAllSuits()
{
foreach (var suit in Enum.GetValues(typeof(Suits)))
{
System.Console.WriteLine(suit.ToString());
}
}
No obtendrá Enum.GetValues()
en Silverlight.
Blog original de 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();
}
}
Sé que es un poco desordenado, pero si eres fanático de las frases simples, aquí tienes una:
((Suit[])Enum.GetValues(typeof(Suit))).ToList().ForEach(i => DoSomething(i));
Si necesita velocidad y verificación de tipos en el tiempo de compilación y ejecución, este método auxiliar es mejor que usar LINQ para lanzar cada elemento:
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[];
}
Y puedes usarlo como a continuación:
static readonly YourEnum[] _values = GetEnumValues<YourEnum>();
Por supuesto, puedes devolver IEnumerable<T>
, pero eso no te compra nada aquí.
Solo para agregar mi solución, que funciona en un marco compacto (3.5) y admite la verificación de tipos en tiempo de compilación :
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 alguien sabe cómo deshacerse de T valueType = new T()
, estaré encantado de ver una solución.
Una llamada se vería así:
List<MyEnum> result = Utils.GetEnumValues<MyEnum>();
También puede enlazar a los miembros estáticos públicos de la enumeración directamente mediante la reflexión:
typeof(Suit).GetMembers(BindingFlags.Public | BindingFlags.Static)
.ToList().ForEach(x => DoSomething(x.Name));
Tres maneras:
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
No estoy seguro de por qué se introdujo GetEnumValues
en la instancia de tipo, no es muy legible para mí.
Tener una clase de ayuda como Enum<T>
es lo más legible y memorable para mí:
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));
}
}
Ahora llamas:
Enum<Suit>.GetValues();
//or
Enum.GetValues(typeof(Suit)); //pretty consistent style
También se puede usar una especie de almacenamiento en caché si el rendimiento es importante, pero no espero que esto sea un problema en absoluto
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)));
}
}
Una forma simple y genérica de convertir una enumeración a algo con lo que puedes interactuar:
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());
}
Y entonces:
var enums = EnumHelper.ToList<MyEnum>();
Utilizo ToString (), luego divido y analizo la matriz de escupir en banderas.
[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);
}
enum
tipos de enum
se denominan "tipos de enumeración" no porque sean contenedores que "enumeren" valores (que no son), sino porque se definen al enumerar los valores posibles para una variable de ese tipo.
(En realidad, eso es un poco más complicado que eso: se considera que los tipos de enumeración tienen un tipo entero "subyacente", lo que significa que cada valor de enumeración corresponde a un valor entero (esto suele ser implícito, pero se puede especificar manualmente). C # fue diseñado de manera que pueda incluir cualquier entero de ese tipo en la variable enum, incluso si no es un valor "con nombre".
El método System.Enum.GetNames se puede usar para recuperar una matriz de cadenas que son los nombres de los valores de enumeración, como sugiere el nombre.
EDITAR: Debería haber sugerido el método System.Enum.GetValues lugar. Ups.
foreach (Suit suit in (Suit[]) Enum.GetValues(typeof(Suit)))
{
}
foreach (Suit suit in Enum.GetValues(typeof(Suit)))
{
}
(La respuesta aceptada actual tiene un elenco que no creo que sea necesario (aunque puede que esté equivocado).)
public void PrintAllSuits()
{
foreach(string suit in Enum.GetNames(typeof(Suits)))
{
Console.WriteLine(suit);
}
}