Iterar sobre todos los valores de un enum es un requisito común en C#. Puede necesitar llenar un menú desplegable, validar una entrada o realizar una acción para cada miembro del enum. Esta guía cubre todos los enfoques para iterar a través de enums, incluyendo auxiliares genéricos y el manejo de enums de flags.
Definiendo un enum de ejemplo
Todos los ejemplos en este artículo utilizan el siguiente enum:
public enum Season
{
Spring,
Summer,
Autumn,
Winter
}
Método 1: Enum.GetValues con foreach
El enfoque más común usa Enum.GetValues, que devuelve un Array con todos los valores definidos en el enum:
foreach (Season season in Enum.GetValues(typeof(Season)))
{
Console.WriteLine(season);
}
Salida:
Spring
Summer
Autumn
Winter
La conversión del Array devuelto a Season es implícita cuando se declara la variable del bucle con el tipo del enum.
Método 2: Genérico Enum.GetValues (.NET 5+)
A partir de .NET 5, está disponible una sobrecarga genérica que devuelve un arreglo fuertemente tipado, eliminando la necesidad de typeof:
foreach (Season season in Enum.GetValues<Season>())
{
Console.WriteLine(season);
}
Este es el enfoque más limpio para aplicaciones .NET modernas.
Método 3: Enum.GetNames
Si solo necesita los nombres en cadena de los miembros del enum, use Enum.GetNames:
foreach (string name in Enum.GetNames(typeof(Season)))
{
Console.WriteLine(name);
}
O con la sobrecarga genérica (.NET 5+):
foreach (string name in Enum.GetNames<Season>())
{
Console.WriteLine(name);
}
Esto devuelve las mismas cadenas que obtendría al llamar .ToString() en cada valor del enum, pero sin la sobrecarga de boxing y unboxing.
Método 4: LINQ con valores de Enum
Puede usar LINQ para filtrar, ordenar o transformar valores de enum:
var warmSeasons = Enum.GetValues<Season>()
.Where(s => s == Season.Spring || s == Season.Summer)
.ToList();
foreach (var season in warmSeasons)
{
Console.WriteLine(season);
}
Creando un diccionario a partir de un Enum
Un patrón común es construir un diccionario que mapee valores enteros a nombres:
var seasonDict = Enum.GetValues<Season>()
.ToDictionary(s => (int)s, s => s.ToString());
// {0: "Spring", 1: "Summer", 2: "Autumn", 3: "Winter"}
Método 5: Conversión a un arreglo para acceso por índice
Si necesita acceder a los valores del enum por índice:
Season[] seasons = (Season[])Enum.GetValues(typeof(Season));
Season third = seasons[2]; // Autumn
int count = seasons.Length; // 4
O con la versión genérica:
Season[] seasons = Enum.GetValues<Season>();
Llenando un menú desplegable desde un Enum
Uno de los usos más comunes en el mundo real es llenar un control de interfaz de usuario:
// Windows Forms ComboBox
comboBox.DataSource = Enum.GetValues<Season>();
// ASP.NET MVC SelectList
var items = Enum.GetValues<Season>()
.Select(s => new SelectListItem
{
Value = ((int)s).ToString(),
Text = s.ToString()
})
.ToList();
Analizando cadenas a valores de Enum
Para convertir una cadena a un valor de enum, use Enum.Parse o Enum.TryParse:
// Throws ArgumentException if invalid
Season parsed = (Season)Enum.Parse(typeof(Season), "Summer");
// Safe parsing (returns false if invalid)
if (Enum.TryParse<Season>("Summer", out Season result))
{
Console.WriteLine(result); // Summer
}
// Case-insensitive parsing
Enum.TryParse<Season>("summer", ignoreCase: true, out Season result2);
Conversión entre Enum y entero
// Enum to int
int value = (int)Season.Autumn; // 2
// Int to enum
Season season = (Season)2; // Autumn
// Check if value is defined
bool isDefined = Enum.IsDefined(typeof(Season), 2); // true
bool isUndefined = Enum.IsDefined(typeof(Season), 99); // false
Trabajando con Enums de Flags
Los enums de flags usan el atributo [Flags] y valores bit a bit, permitiendo combinaciones:
[Flags]
public enum FilePermissions
{
None = 0,
Read = 1,
Write = 2,
Execute = 4,
All = Read | Write | Execute
}
Iterando flags individuales
Enum.GetValues devuelve todos los valores definidos, incluyendo combinaciones como All. Para iterar solo las flags individuales que están establecidas en un valor dado:
FilePermissions perms = FilePermissions.Read | FilePermissions.Write;
foreach (FilePermissions flag in Enum.GetValues<FilePermissions>())
{
if (flag != FilePermissions.None && perms.HasFlag(flag))
{
Console.WriteLine(flag);
}
}
// Output: Read, Write
Verificando flags individuales
FilePermissions perms = FilePermissions.Read | FilePermissions.Execute;
bool canRead = perms.HasFlag(FilePermissions.Read); // true
bool canWrite = perms.HasFlag(FilePermissions.Write); // false
bool canExecute = perms.HasFlag(FilePermissions.Execute); // true
Métodos auxiliares genéricos
Puede crear métodos auxiliares reutilizables para operaciones con enums:
public static class EnumHelper
{
/// <summary>
/// Gets all values of an enum as a typed list.
/// </summary>
public static List<T> GetAllValues<T>() where T : struct, Enum
{
return Enum.GetValues<T>().ToList();
}
/// <summary>
/// Gets a dictionary mapping enum names to values.
/// </summary>
public static Dictionary<string, T> GetNameValuePairs<T>() where T : struct, Enum
{
return Enum.GetValues<T>()
.ToDictionary(e => e.ToString(), e => e);
}
/// <summary>
/// Safely parses a string to an enum, returning a default value if parsing fails.
/// </summary>
public static T ParseOrDefault<T>(string value, T defaultValue = default)
where T : struct, Enum
{
return Enum.TryParse<T>(value, ignoreCase: true, out T result)
? result
: defaultValue;
}
}
Uso:
List<Season> allSeasons = EnumHelper.GetAllValues<Season>();
Season parsed = EnumHelper.ParseOrDefault<Season>("summer", Season.Spring);
Referencia rápida
| Tarea | Método |
|---|---|
| Iterar todos los valores | Enum.GetValues<T>() |
| Iterar todos los nombres | Enum.GetNames<T>() |
| Analizar cadena a enum | Enum.TryParse<T>(string, out T) |
| Enum a int | (int)enumValue |
| Int a enum | (T)intValue |
| Verificar si un valor está definido | Enum.IsDefined(typeof(T), value) |
| Verificar si una flag está establecida | value.HasFlag(flag) |
Resumen
La forma más sencilla de iterar a través de un enum en C# es foreach (var value in Enum.GetValues<T>()) en .NET 5 y posterior, o Enum.GetValues(typeof(T)) en frameworks más antiguos. Use Enum.GetNames cuando solo necesite los nombres en cadena, y use el atributo [Flags] con HasFlag para combinaciones bit a bit de enums. Para código reutilizable, cree métodos auxiliares genéricos con la restricción where T : struct, Enum.