Avatar ·

Как перебрать все значения перечисления (enum) в C#?

Всем привет! Я новичок в C# и столкнулся с такой задачей: у меня есть перечисление (enum) для дней недели: ```csharp public enum DaysOfWeek { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } ``` Мне нужно вывести все дни недели на экран или, например, заполнить выпадающий список (ComboBox) в WinForms. Пока я делаю это вручную, но это неудобно и негибко — если я добавлю новый день, придётся везде править код. Я пробовал написать простой цикл, но компилятор ругается, что нельзя использовать `DaysOfWeek` как коллекцию: ```csharp foreach (var day in DaysOfWeek) // Ошибка: foreach не может работать с типом DaysOfWeek { Console.WriteLine(day); } ``` Подскажите, пожалуйста, как правильно перебрать все значения перечисления в 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));
}

Этот подход удобен, когда нужно отображать пользователю понятные строки вместо технических имён констант.