Как перебрать все значения перечисления (enum) в C#?
Использование Enum.GetValues — основной способ
В C# для перебора всех значений перечисления используется статический метод Enum.GetValues<T>() (доступен с .NET 5 и выше) или его неуниверсальная версия Enum.GetValues(Type). Этот метод возвращает массив всех констант перечисления в порядке их объявления.
Вот как исправить ваш пример:
public enum DaysOfWeek
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
// Современный способ (C# 9+, .NET 5+)
foreach (var day in Enum.GetValues<DaysOfWeek>())
{
Console.WriteLine(day); // Выведет: Monday, Tuesday, ...
}
// Классический способ (работает во всех версиях)
foreach (DaysOfWeek day in Enum.GetValues(typeof(DaysOfWeek)))
{
Console.WriteLine(day);
}
Как это работает и что важно знать
- Порядок элементов:
Enum.GetValuesвозвращает элементы в том же порядке, в котором они объявлены в коде (по возрастанию числового значения, если оно не задано явно). - Тип возвращаемого значения: Универсальная версия возвращает
T[], неуниверсальная —Array, который нужно кастить или использоватьforeachс явным указанием типа. - Производительность: Метод кэширует результат, поэтому многократный вызов не создаёт новый массив каждый раз.
Практический пример: заполнение ComboBox
// WinForms
comboBoxDays.Items.Clear();
comboBoxDays.Items.AddRange(Enum.GetValues<DaysOfWeek>().Cast<object>().ToArray());
// WPF
comboBoxDays.ItemsSource = Enum.GetValues<DaysOfWeek>();
comboBoxDays.SelectedIndex = 0;
Что делать, если нужно получить имена или числовые значения?
// Получить имена как строки
string[] names = Enum.GetNames<DaysOfWeek>();
// Получить числовые значения (int)
int[] values = (int[])Enum.GetValues(typeof(DaysOfWeek));
// Или через LINQ
var items = Enum.GetValues<DaysOfWeek>()
.Select(d => new { Name = d.ToString(), Value = (int)d })
.ToList();
Обработка флаговых перечислений (Flags)
Если ваш enum помечен атрибутом [Flags], то Enum.GetValues всё равно вернёт только отдельные константы, определённые в коде. Для получения всех возможных комбинаций используйте другой подход:
[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Execute = 4
}
// Перебор отдельных флагов
foreach (Permissions perm in Enum.GetValues<Permissions>())
{
if (perm != Permissions.None) // Пропускаем 0
Console.WriteLine(perm);
}
Этот метод — стандартный идиоматический способ в C#. Он работает быстро, читается легко и поддерживается во всех версиях .NET.
<<Альтернативный подход: рефлексия и кэширование
Если по какой-то причине Enum.GetValues вам не подходит (например, нужно строго контролировать порядок или исключить некоторые значения), можно использовать рефлексию:
public static class EnumHelper
{
public static T[] GetValues<T>() where T : Enum
{
return typeof(T)
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Select(f => (T)f.GetValue(null))
.ToArray();
}
}
// Использование
var days = EnumHelper.GetValues<DaysOfWeek>();
foreach (var day in days)
{
Console.WriteLine(day);
}
Дополнение: работа с описаниями (Description)
Часто требуется выводить не имена констант, а их локализованные описания. Для этого используется атрибут Description:
public enum DaysOfWeek
{
[Description("Понедельник")]
Monday,
[Description("Вторник")]
Tuesday
// ...
}
public static string GetDescription(Enum value)
{
var field = value.GetType().GetField(value.ToString());
var attr = field.GetCustomAttribute<DescriptionAttribute>();
return attr?.Description ?? value.ToString();
}
// Перебор с описаниями
foreach (var day in Enum.GetValues<DaysOfWeek>())
{
Console.WriteLine(GetDescription(day));
}
Этот подход удобен, когда нужно отображать пользователю понятные строки вместо технических имён констант.