Перечисления enum
Чему вы научитесь:
- объявлять перечисление
enumи выбирать одно значение из его списка; - описывать данные записью
recordи сравнивать записи по содержимому; - получать изменённую копию записи выражением
with; - проверять значения паттернами в
isи в выраженииswitch, помня, что ветви проверяются сверху вниз.

Представьте склад службы доставки. Размер коробки там не пишут от руки, а ставят штампом, и штампов на подставке ровно три: «маленькая», «средняя» и «большая». Своё слово штампом не поставишь, поэтому опечатки вроде «сердняя» на коробке не бывает.
Без штампов размер пришлось бы писать от руки, а в программе — хранить строкой или числом. Строка "Meduim" с опечаткой компилируется без единого предупреждения. Число 1 ничего не говорит читателю: это маленькая коробка или средняя?
Тип, у которого есть только заранее названные значения, называется перечислением. В C# его объявляют словом enum:
Size box = Size.Medium;
Console.WriteLine(box); // Medium
if (box == Size.Medium)
{
Console.WriteLine("medium box"); // medium box
}
enum Size { Small, Medium, Large }Давайте разберём программу по строкам:
enum Size { Small, Medium, Large }объявляет типSizeс тремя значениями. Как и класс, перечисление объявляют после инструкций верхнего уровня.Size box = Size.Medium;создаёт переменную типаSize. Значение пишут через точку: имя перечисления, затем имя значения.Console.WriteLine(box)печатает имя значения:Medium.box == Size.Mediumсравнивает два значения перечисления и даётtrue, поэтому выполняется веткаif.
Объявление перечисления
Разберём объявление enum Size { Small, Medium, Large } по частям:
enum— ключевое слово: после него идёт имя нового типа;Size— имя типа, с большой буквы, как у класса;Small,Medium,Large— члены перечисления, через запятую в фигурных скобках; их тоже называют с большой буквы.
Опечатку теперь поймает компилятор. Строка Size box = Size.Meduim; не скомпилируется: компилятор выдаст ошибку CS0117, потому что члена Meduim в типе Size нет.
Число за каждым именем
Внутри перечисление хранит целое число типа int. Члены нумеруются по порядку с нуля: Small — это 0, Medium — 1, Large — 2. Номер получают приведением (int), а обратно, от числа к члену, ведёт приведение к типу перечисления:
Console.WriteLine((int)Size.Large); // 2
Console.WriteLine((Size)1); // Medium
Console.WriteLine((int)Status.Archived); // 6
enum Status { Draft = 1, Published = 5, Archived }Номер можно задать и самому, как Draft = 1. Член без номера получает номер предыдущего члена плюс один, поэтому Archived — это 6.
На собеседовании любят спросить, что хранится внутри enum. Ответ: целое число, а имена нужны для чтения кода и для печати. Если не задать числу другой тип, это int. Значение по умолчанию у любого перечисления — 0. Если члена с номером 0 нет, как в Status, значение по умолчанию печатается цифрой 0.
Число без имени
Здесь аналогия со штампами перестаёт работать. Нельзя поставить штамп, которого нет на подставке. Переменная-перечисление так не защищена: приведением в неё можно положить любое число типа int, даже если у него нет имени.
Size odd = (Size)7;
Console.WriteLine(odd); // 7
Console.WriteLine(odd switch
{
Size.Small => "S",
Size.Medium => "M",
Size.Large => "L",
_ => "unknown",
}); // unknownКомпилятор не проверяет, есть ли у числа имя: приведение явное, и за него отвечаете вы. Console.WriteLine печатает значение без имени цифрами, поэтому выводится 7.
Переменная-перечисление может хранить число без имени, поэтому выражению switch по перечислению нужна ветвь _, даже когда у каждого члена есть своя ветвь. Без неё компилятор выдаст предупреждение CS8524: число без имени, например (Size)3, не обработано.
Частая ошибка
Число положили в переменную-перечисление без приведения:
Size box = 2; // ✗
Console.WriteLine(box);
enum Size { Small, Medium, Large }error CS0266: Cannot implicitly convert type 'int' to 'Size'. An explicit conversion exists (are you missing a cast?)Программа не компилируется. Число не превращается в перечисление само, иначе случайная 2 тихо стала бы размером коробки. Нужно явное приведение (Size)2, а лучше — имя члена: Size.Large. Исключение одно — ноль: компилятор переводит литерал 0 или константу, равную нулю, в любое перечисление без приведения.
Главное
enumобъявляет тип с фиксированным набором именованных значений:enum Size { Small, Medium, Large }.- За каждым членом стоит число типа
int: по умолчанию0,1,2по порядку, и(int)Size.Largeдаёт2. Console.WriteLineпечатает имя члена, а число без имени — цифрами:(Size)7выводится как7.- Число попадает в перечисление через явное приведение:
Size box = 2;не компилируется.