Перейти к содержимому
Теория · Условия и циклы · урок 3 из 13

Инструкция switch

В прошлом уроке цепочка if и else if выбирала ветку по условиям. Часто эти условия похожи друг на друга: одну и ту же переменную сравнивают с разными значениями.

Представьте лифт в офисном здании. На панели по кнопке на каждый этаж: на первом холл, на третьем кафе, на остальных офисы. Вы нажимаете «3», и лифт едет сразу на третий этаж, не останавливаясь на каждом, чтобы спросить, ваш ли это.

Цепочка else if похожа на лифт, который всё-таки останавливается на каждом этаже: она снова и снова сравнивает одну и ту же переменную. Инструкция switch работает как панель лифта: вычисляет значение один раз и переходит к ветке с таким же значением.

C#
int floor = 3;

switch (floor)
{
    case 1:
        Console.WriteLine("Lobby");
        break;
    case 3:
        Console.WriteLine("Cafe"); // Cafe
        break;
    default:
        Console.WriteLine("Offices");
        break;
}

Строки case 1:, case 3: и default: называют метками: каждая отмечает, где начинается её ветка.

Давайте пройдём по программе:

  1. switch (floor) вычисляет floor и получает 3.
  2. Метка case 1: не совпадает с 3, и её код не выполняется.
  3. Метка case 3: совпадает, поэтому выполняется код под ней: программа выводит Cafe.
  4. break завершает switch, и программа переходит к коду после закрывающей скобки.

При floor = 1 программа выведет Lobby, а любое число, кроме 1 и 3, даст Offices.

Метки case и default

Код под меткой называют веткой, как и в if. В switch два вида меток.

Метка case

После слова case стоит значение и двоеточие, а ниже — код ветки. Метка case проверяет, равно ли значение в скобках switch её значению.

Значение после case должно быть известно ещё при компиляции: число, символ, строка в кавычках или константа, объявленная через const. Обычную переменную там компилятор не примет. Два case с одинаковым значением тоже не скомпилируются.

Метка default

Ветка default выполняется, когда не подошёл ни один case, как else в цепочке if. Обычно её ставят последней.

Если ни один case не подошёл, а ветки default нет, не выполняется ничего. Программа идёт дальше, к коду после закрывающей скобки switch.

Ветка должна закончиться

В C# каждая ветка обязана выйти из switch, и в этой теме для этого служит break. Выполнение не может перетечь из одной ветки в следующую: если ветка заканчивается без break, программа не компилируется. Правило касается и последней ветки, даже default.

Об этом часто спрашивают на собеседовании. В C, C++ и Java ветка без break молча продолжается кодом следующей ветки, и забытый break превращается в ошибку, которую трудно найти. C# такое продолжение запрещает, поэтому забытый break находит компилятор.

Несколько меток у одной ветки

У правила всё же есть оговорка. Если под меткой нет ни одной инструкции, она относится к ветке ниже. Так несколько значений получают общий код:

C#
int day = 6;

switch (day)
{
    case 6:
    case 7:
        Console.WriteLine("weekend"); // weekend
        break;
    default:
        Console.WriteLine("workday");
        break;
}

Разберём, что происходит:

  1. day равен 6, и выполнение начинается с метки case 6:.
  2. Под ней нет инструкций: метки case 6: и case 7: стоят над одной веткой.
  3. Программа выводит weekend, а break завершает switch.

Здесь аналогия с лифтом перестаёт работать. За кнопкой лифта стоит один этаж, а у ветки switch может быть несколько меток, и все они ведут в одно место.

switch по строке

Значением в switch может быть не только число, но и строка. Тогда в метках case стоят строки в кавычках:

C#
string command = "stop";

switch (command)
{
    case "start":
        Console.WriteLine("Starting");
        break;
    case "stop":
        Console.WriteLine("Stopping"); // Stopping
        break;
    default:
        Console.WriteLine("Unknown command");
        break;
}

Строки сравниваются целиком и с учётом регистра. Если в command окажется "Stop" с заглавной буквы, ни один case не подойдёт, и программа выведет Unknown command.

Частая ошибка

В ветке забыли break:

C#
int level = 1;

switch (level)
{
    case 1:
        Console.WriteLine("beginner"); // ✗
    case 2:
        Console.WriteLine("advanced");
        break;
}
TEXT
error CS0163: Control cannot fall through from one case label ('case 1:') to another

Программа не компилируется. Сообщение значит: «выполнение не может перейти от одной метки case к другой». Ветка case 1: заканчивается без break, и компилятор не даёт ей продолжиться кодом ветки case 2:. Чтобы программа скомпилировалась, допишите break после Console.WriteLine("beginner").

Главное

  • switch вычисляет значение один раз и выполняет ветку с совпадающим case, а если такой нет — ветку default.
  • После case стоит значение, известное при компиляции: число, символ, строка или константа const.
  • Каждая ветка заканчивается break: без него программа не компилируется.
  • Несколько меток подряд без инструкций между ними ведут к одной ветке.