JavaRush /Курси /C# SELF /Перерахування (enum) у C#: зручні іменовані константи

Перерахування (enum) у C#: зручні іменовані константи

C# SELF
Рівень 10 , Лекція 4
Відкрита

1. Вступ

У програмуванні часто доводиться працювати зі списками наперед відомих, обмежених варіантів. Наприклад — дні тижня, кольори світлофора, рівні складності гри, статуси замовлення. Кожен із цих варіантів зазвичай подано фіксованим значенням. Ось тут ми й підходимо ближче до нашої сьогоднішньої теми — перерахувань (enum).

Перерахування — це спеціальний тип даних, який дає змогу оголошувати набір іменованих констант.
enum — як коробка з розкладеними по комірках ярликами, де кожен ярлик — унікальне імʼя, пов’язане з числом.

  • Ваш код стає читабельним і самодокументованим;
  • Замість загадкових «магічних чисел» на кшталт 0, 1, 2 з’являються виразні імена: DayOfWeek.Monday або TrafficLight.Red;
  • Компілятор повідомить про помилку, якщо ви спробуєте присвоїти некоректне значення;
  • За кожним елементом ховається… звичайне ціле число! (Але до цього ми ще повернемося.)

2. Синтаксис оголошення перерахування

Створімо перше перерахування — типи погоди для нашого майбутнього застосунку. Ось як це виглядає:


// Перерахування погодних умов
public enum WeatherCondition
{
    Sunny,       // 0
    Cloudy,      // 1
    Rainy,       // 2
    Stormy,      // 3
    Snowy        // 4
}
Оголошення перерахування WeatherCondition
  • Ключове слово enum визначає новий тип.
  • У фігурних дужках — імена варіантів. За замовчуванням кожному варіанту відповідає ціле число, починаючи з нуля (Sunny == 0, Cloudy == 1 тощо).
  • Можна явно задати значення:
public enum WeatherCondition
{
    Sunny = 1,
    Cloudy = 2,
    Rainy = 4,
    Stormy = 8,
    Snowy = 16
}

Це зручно, якщо значення мають відповідати певним зовнішнім стандартам або протоколам.

3. Використання перерахувань

Уявімо, що ми написали застосунок — невеличку консольну програму, яка реагує на погоду.

// Клас застосунку
class Program
{
    static void Main()
    {
        // Використовуємо наше перерахування для зберігання стану погоди
        WeatherCondition todayWeather = WeatherCondition.Sunny;

        // Виведемо на екран
        Console.WriteLine($"Сьогодні погода: {todayWeather} ({(int)todayWeather})");

        // А тепер зімітуємо зміну погоди
        todayWeather = WeatherCondition.Rainy;
        Console.WriteLine($"Ой! Погода змінилася: {todayWeather} ({(int)todayWeather})");
    }
}

Що відбудеться?


Сьогодні погода: Sunny (0)
Ой! Погода змінилася: Rainy (2)
  • todayWeather — це не рядок, не число, а елемент перерахування.
  • Приведення типу до (int) дає змогу побачити «числовий» код цього значення.

До речі, перерахування чудово поєднуються з умовами:

if (todayWeather == WeatherCondition.Rainy)
    Console.WriteLine("Візьміть парасолю!");

4. Практичні сценарії використання enum

Де зустрічаються перерахування?

  • У бізнес-застосунках: статуси замовлень (New, Processing, Shipped, Cancelled).
  • У системах керування користувачами: рівні доступу (User, Moderator, Admin).
  • В іграх: стани персонажа (Idle, Moving, Jumping, Falling).
  • У GUI: кнопки, повідомлення, кольори іконок.

А якщо копнути у .NET — ви знайдете їх майже в кожному другому класі стандартної бібліотеки! Наприклад, у файлових операціях є перерахування для вказання режиму відкриття файлу (читання, запис, створення).

5. Явні значення та діапазон значень

Іноді варто перетворити набір значень типу int, що використовуються у вашому коді, на enum. Зробити це дуже просто:


public enum CompassDirection
{
    North = 10,
    East = 20,
    South = 30,
    West = 40
}
Перерахування з явними значеннями

Тепер CompassDirection.North = 10, East = 20, тощо. Якщо якийсь елемент не вказано явно, він автоматично отримує значення +1 від попереднього.

Тип зберігання

За замовчуванням enum зберігається як int (4-байтове ціле число). Але ви можете вказати власний базовий тип, якщо хочете заощадити пам’ять:

public enum TinyEnum : byte
{
    First,  // 0
    Second, // 1
    Third   // 2
}

Тепер кожне значення перерахування — лише один байт!

Повний список можливих типів: byte, sbyte, short, ushort, int, uint, long, ulong.

6. Перетворення між enum і числами/рядками

Перетворення enumint:

Щоб перетворити enum на int і навпаки, можна просто використати приведення типу:

WeatherCondition current = WeatherCondition.Cloudy;
int number = (int)current; // Отримаємо 1

WeatherCondition fromNumber = (WeatherCondition)2; // Отримаємо Rainy

Перетворення enumstring:

Перетворити enum у рядок легко: достатньо викликати метод ToString().

// Перетворюємо enum у рядок
string name = WeatherCondition.Stormy.ToString(); // "Stormy"

// Перетворюємо рядок у enum за допомогою Enum.Parse
WeatherCondition parsed = (WeatherCondition)Enum.Parse(typeof(WeatherCondition), "Stormy");

// Також можна використати Enum.TryParse
WeatherCondition parsedOk;
if (Enum.TryParse("Snowy", out parsedOk))
{
    Console.WriteLine(parsedOk); // Snowy
}

Типова помилка:
Якщо ви перетворите число на enum, для якого не визначено такого члена, компілятор не повідомить про помилку, але ви отримаєте «віртуальний» стан.
Наприклад:

WeatherCondition weird = (WeatherCondition)999;
Console.WriteLine(weird); // 999 (воно не перетвориться на «Unknown»!)

Отже, під час таких перетворень слід бути уважними.

7. switch і enum створені одне для одного

Перерахування (enum) чудово поєднуються з оператором switch. Це зручний і наочний спосіб «реагувати» на різні значення перерахування — без довгих «if-else».

Приклад: реакція на погоду

public enum WeatherCondition
{
    Sunny,
    Cloudy,
    Rainy,
    Stormy,
    Snowy
}

WeatherCondition today = WeatherCondition.Rainy;

switch (today)
{
    case WeatherCondition.Sunny:
        Console.WriteLine("Сонячно! Можна йти гуляти.");
        break;
    case WeatherCondition.Cloudy:
        Console.WriteLine("Похмуро. Можна взяти кофту.");
        break;
    case WeatherCondition.Rainy:
        Console.WriteLine("Йде дощ. Не забудьте парасолю!");
        break;
    case WeatherCondition.Stormy:
        Console.WriteLine("Шторм! Краще залишитися вдома.");
        break;
    case WeatherCondition.Snowy:
        Console.WriteLine("Сніг іде — одягніть шапку!");
        break;
    default:
        Console.WriteLine("Невідома погода...");
        break;
}
  • Кожен випадок (case) відповідає одному значенню перерахування.
  • Якщо значення не збігається ні з одним із відомих варіантів, виконується default (це корисно, якщо раптом у змінну потрапило щось неочікуване).

Чим крута зв’язка enum + switch?

  • Код читабельний: усі можливі варіанти одразу видно за списком case.
  • Зручно розширювати: додали новий тип погоди — просто додайте ще один case.
  • Безпека: компілятор попередить, якщо ви забули обробити всі варіанти (починаючи з C# 8.0, можна навіть увімкнути перевірку на вичерпність).

Приклад: enum з логікою для гри

public enum GameState
{
    Start,
    Playing,
    Paused,
    GameOver
}

void PrintState(GameState state)
{
    switch (state)
    {
        case GameState.Start:
            Console.WriteLine("Ласкаво просимо до гри!");
            break;
        case GameState.Playing:
            Console.WriteLine("Гра триває. Успіхів!");
            break;
        case GameState.Paused:
            Console.WriteLine("Пауза. Можна перепочити.");
            break;
        case GameState.GameOver:
            Console.WriteLine("Гру завершено. Спробуйте ще раз!");
            break;
        default:
            Console.WriteLine("Невідомий стан гри.");
            break;
    }
}

Поради:

  • Якщо у вас багато схожих дій для кількох варіантів, їх можна об’єднувати:
switch (today)
{
    case WeatherCondition.Rainy:
    case WeatherCondition.Stormy:
        Console.WriteLine("Не забудьте парасолю й теплий одяг!");
        break;
}
  • Не забувайте про default, щоб обробити неочікувані значення (наприклад, якщо хтось перетворив число на enum напряму).
  • Зі switch зручно будувати «машини станів», меню й будь-які системи зі фіксованим набором варіантів.

8. Перерахування і основні методи/сервіси .NET

.NET надає чимало корисних методів для перерахувань:

  • Enum.GetNames(typeof(WeatherCondition)) — отримати всі імена.
  • Enum.GetValues(typeof(WeatherCondition)) — усі значення.
  • Enum.IsDefined(typeof(WeatherCondition), "Rainy") — дізнатися, чи є в перерахуванні такий член.
  • Документація: System.Enum

Приклад виведення всіх варіантів погоди:

foreach (var name in Enum.GetNames(typeof(WeatherCondition)))
{
    Console.WriteLine(name);
}

9. Часті помилки й «підводні камені»

  • Використовують «магічні числа» замість перерахувань, втрачаючи читабельність.
  • Не обробляють значення, які не визначені в перерахуванні (див. пункт із перетворенням числа).
  • Називають елементи перерахування невідповідно до їхнього змісту (Value1, Value2... — і вже ніхто не пам’ятає, що це означає).
  • Порушують принцип єдиної відповідальності — використовують одне перерахування для різних речей.

Найкраще рішення: завжди використовуйте перерахування, коли набір варіантів є скінченним, і надавайте елементам змістовні, самодокументовані імена.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ