Выражение switch
В прошлом уроке инструкция switch выбирала, какой код выполнить. Часто нужно другое: по номеру этажа получить его название и сохранить в переменной. С инструкцией switch для этого понадобились бы переменная, присваивание в каждой ветке и break после каждого присваивания.
Вернёмся к лифту. Рядом с кнопками висит табличка: «1 — холл, 3 — кафе, остальные — офисы». Табличка ничего не делает, она только отвечает: назовите этаж — получите название. Выражение switch устроено как такая табличка: по значению оно выдаёт результат.
int floor = 3;
string name = floor switch
{
1 => "Lobby",
3 => "Cafe",
_ => "Offices",
};
Console.WriteLine(name); // CafeДавайте разберём программу:
floor switch { … }берёт значениеfloor, то есть3, и ищет подходящую строку таблички.- Строка
1 => "Lobby"не подходит:3не равно1. - Строка
3 => "Cafe"подходит, и всё выражение получает значение"Cafe". - Это значение попадает в переменную
name, и программа выводитCafe.
Из чего состоит выражение switch
Каждая строка вида 3 => "Cafe" называется ветвью выражения. Вся конструкция складывается из четырёх частей:
- значение перед словом
switch— то, что проверяют, здесьfloor; - ветви в фигурных скобках: слева от
=>значение, справа результат, а после ветви запятая; - ветвь
_— «всё остальное»: она подходит к любому значению, какdefaultв инструкцииswitch; - точка с запятой после закрывающей скобки: весь код от
string nameдо;— одна инструкция.
Ветви проверяются сверху вниз, и выигрывает первая подходящая. Поэтому _ ставят последней. Ветвь ниже неё не сработала бы никогда, и компилятор такой код не примет.
Все результаты должны подходить переменной слева. Здесь каждая ветвь даёт строку, и ветвь с числом 3 => 42 не скомпилировалась бы.
Выражение и инструкция
Это та же пара, что if и ?:: инструкция выполняет код, а у выражения есть значение. Значение выражения switch можно не сохранять в переменной, а сразу передать в Console.WriteLine:
int day = 7;
Console.WriteLine(day switch
{
6 => "Saturday",
7 => "Sunday",
_ => "workday",
}); // SundayВыражение day switch { … } даёт "Sunday", и это значение сразу уходит в Console.WriteLine.
В ветви выражения стоит одно значение, а не инструкции: ни break, ни несколько строк кода туда не поставить. Когда в каждом случае нужно выполнить несколько действий, берут инструкцию switch.
На собеседовании иногда спрашивают, чем выражение switch отличается от инструкции switch. Короткий ответ: инструкция выполняет код ветки, а выражение вычисляет значение, и ветвям не нужен break.
Здесь аналогия с табличкой перестаёт работать. Если строки для этажа на табличке нет, табличка молчит. Выражение switch молчать не может: без подходящей ветви оно останавливает программу.
Частая ошибка
Забыли ветвь _:
int floor = 4;
string name = floor switch // ✗
{
1 => "Lobby",
3 => "Cafe",
};
Console.WriteLine(name);warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '0' is not covered.Программа компилируется, но с этим предупреждением: компилятор заметил, что для 0 и многих других чисел ветви нет. При запуске с floor = 4 ни одна ветвь не подходит, и программа останавливается на этой строке с исключением:
Unhandled exception. System.Runtime.CompilerServices.SwitchExpressionException: Non-exhaustive switch expression failed to match its input.Инструкция switch без default в таком случае не выполнила бы ничего. Выражению же обязательно нужно значение для name, а взять его негде. Добавьте ветвь _ => "Offices", и исчезнут и предупреждение, и исключение.
Главное
- Выражение
switchвыбирает результат по значению:floor switch { 1 => "Lobby", _ => "Offices" }. - Ветви проверяются сверху вниз; ветвь
_подходит к любому значению и стоит последней. - Инструкция
switchвыполняет код ветки, а выражениеswitchдаёт значение, иbreakему не нужен. - Без подходящей ветви программа останавливается с исключением
SwitchExpressionException, и компилятор заранее предупреждает об этом:CS8509.