$ sudo teach IT
Модуль 3 · Условный оператор

Урок 3.6 — Оператор switch

Множественный выбор без цепочек if. От классического switch до pattern matching.

Когда нужно проверить переменную на множество возможных значений, цепочка if-else if становится громоздкой. Представь: «если день 1 — понедельник, если 2 — вторник... если 7 — воскресенье». Семь if-else — это много кода и плохая читаемость. C# предлагает элегантное решение — оператор switch.

🔀

Синтаксис switch

Switch проверяет выражение и сравнивает его с несколькими возможными значениями (case). Вот базовая структура:

Общая схема:

switch (выражение)
{
    case значение1:
        // код для значения1
        break;
    case значение2:
        // код для значения2
        break;
    default:
        // код, если ни один case не подошёл
        break;
}
C# · Дни недели через switch
int dayNumber = 3;
string dayName;

switch (dayNumber)
{
    case 1:
        dayName = "Понедельник";
        break;
    case 2:
        dayName = "Вторник";
        break;
    case 3:
        dayName = "Среда";
        break;
    case 4:
        dayName = "Четверг";
        break;
    case 5:
        dayName = "Пятница";
        break;
    case 6:
        dayName = "Суббота";
        break;
    case 7:
        dayName = "Воскресенье";
        break;
    default:
        dayName = "Неизвестный день";
        break;
}

Console.WriteLine(dayName);  // Среда
💡 Ключевое слово break обязательно после каждого case. Оно говорит C#: «выполнили код для этого case — выходи из switch». Если забыть break, C# выдаст ошибку компиляции (в отличие от C/C++, где код «проваливается» дальше).
⚖️

Отличие switch от if-else if

Когда использовать switch, а когда if-else if? Вот ключевые различия:

if-else if
switch
Проверяет любые условия (>, <, !=, &&, ||)
Проверяет только равенство (==) с константами
Может проверять диапазоны (age >= 18)
Диапазоны — только через pattern matching (C# 7+)
Громоздкий при 5+ вариантах
Компактный и читаемый при многих вариантах
Гибче — любое условие
Быстрее — оптимизируется компилятором

💡 Простое правило: если ты проверяешь одну переменную на равенство с константами (1, 2, 3 или "красный", "зелёный", "синий") — используй switch. Если условие сложнее (диапазоны, комбинации) — if-else if.

🚫

Case-блоки и обязательный break

В C# каждый case-блок обязательно должен заканчиваться одним из:

  • break; — выход из switch
  • return; — выход из метода
  • throw; — выброс исключения
  • goto case X; — переход к другому case (существует, но использовать редко)
C# · Обязательный break
// ❌ Так нельзя — ошибка компиляции!
// switch (x)
// {
//     case 1:
//         Console.WriteLine("Один");
//         // забыли break!
//     case 2:
//         Console.WriteLine("Два");
//         break;
// }

// ✅ Так правильно:
switch (x)
{
    case 1:
        Console.WriteLine("Один");
        break;
    case 2:
        Console.WriteLine("Два");
        break;
}
📋

Default-ветка

Блок default — аналог else в if-else. Он выполняется, если ни один из case не подошёл. default необязателен, но его рекомендуется добавлять всегда — на случай непредвиденных значений.

C# · Default в action
Console.Write("Введите оценку (1-5): ");
int grade = Convert.ToInt32(Console.ReadLine());

switch (grade)
{
    case 5:
        Console.WriteLine("Отлично!");
        break;
    case 4:
        Console.WriteLine("Хорошо");
        break;
    case 3:
        Console.WriteLine("Удовлетворительно");
        break;
    case 2:
    case 1:
        Console.WriteLine("Неудовлетворительно");
        break;
    default:
        Console.WriteLine("Некорректная оценка!");
        break;
}
🔢

Switch с множественными значениями (case 1: case 2:)

Если несколько значений должны приводить к одному результату, можно перечислить их подряд (в C# это разрешено, если объединяемые case пустые, без кода):

C# · Группировка case
string category = "fruit";

switch (category)
{
    case "apple":
    case "banana":
    case "orange":
        Console.WriteLine("Это фрукт");
        break;
    case "carrot":
    case "broccoli":
    case "potato":
        Console.WriteLine("Это овощ");
        break;
    default:
        Console.WriteLine("Неизвестная категория");
        break;
}
💡 Обрати внимание: у case "apple" нет ни кода, ни break — он просто «проваливается» в следующий case, где есть код. Это единственный разрешённый вид проваливания в C#. Код пишется только в последнем объединённом case.
🎯

Pattern matching в switch (C# 7+)

Начиная с C# 7, switch стал гораздо мощнее. Теперь можно проверять не только равенство, но и тип переменной, а также добавлять дополнительные условия (when):

C# 7+ · Pattern matching в switch
object value = 42;

switch (value)
{
    case int i when i > 0:
        Console.WriteLine($"Положительное целое: {i}");
        break;
    case int i when i < 0:
        Console.WriteLine($"Отрицательное целое: {i}");
        break;
    case int i:
        Console.WriteLine($"Целое число: {i}");
        break;
    case string s:
        Console.WriteLine($"Строка: {s}");
        break;
    case double d:
        Console.WriteLine($"Дробное: {d}");
        break;
    case null:
        Console.WriteLine("null");
        break;
    default:
        Console.WriteLine("Неизвестный тип");
        break;
}

Ключевое слово when добавляет дополнительное условие к case. Это как if внутри case. Порядок case важен: более конкретные условия должны быть выше.

💡 Pattern matching позволяет использовать switch не только с примитивными типами, но и с объектами, проверяя их тип и свойства. Это особенно полезно при работе с иерархиями классов (полиморфизм).

⚡

Switch-выражение (C# 8+)

Начиная с C# 8, появился switch как выражение. Он возвращает значение и записывается в компактной форме. Это как тернарный оператор, но для множества вариантов:

C# 8+ · Switch-выражение
// Старый switch (оператор):
string GetDayOld(int day)
{
    switch (day)
    {
        case 1: return "Пн";
        case 2: return "Вт";
        case 3: return "Ср";
        case 4: return "Чт";
        case 5: return "Пт";
        case 6: return "Сб";
        case 7: return "Вс";
        default: return "?";
    }
}

// Новый switch (выражение), C# 8+:
string GetDayNew(int day) => day switch
{
    1 => "Пн",
    2 => "Вт",
    3 => "Ср",
    4 => "Чт",
    5 => "Пт",
    6 => "Сб",
    7 => "Вс",
    _ => "?"
};

Console.WriteLine(GetDayNew(3));  // Ср

Ключевые отличия switch-выражения:

  • Используется стрелка => вместо двоеточия :
  • Нет break — каждый вариант сам возвращает значение
  • Нет case — пишется значение сразу
  • _ — это discard (аналог default)
  • Это выражение, его можно присвоить переменной
C# 8+ · Пример с when в выражении
// Switch-выражение с дополнительными условиями
string GetCategory(int score) => score switch
{
    >= 90 => "Отлично",
    >= 75 => "Хорошо",
    >= 50 => "Удовлетворительно",
    _ => "Неудовлетворительно"
};

Console.WriteLine(GetCategory(85));  // Хорошо

// Можно комбинировать с паттернами типов:
object obj = 3.14;
string description = obj switch
{
    int i => $"Целое: {i}",
    double d => $"Дробное: {d}",
    string s => $"Строка: {s}",
    _ => "Неизвестный тип"
};

Console.WriteLine(description);  // Дробное: 3.14
💡 Switch-выражения — современный стандарт в C#. Они делают код компактным и выразительным. Старайся использовать их вместо классического switch, когда нужно вернуть одно значение.
🛠️

Сводный пример — калькулятор

Напишем простой калькулятор с switch:

C# · Калькулятор на switch
using System;

class Program
{
    static void Main()
    {
        Console.Write("Введите первое число: ");
        double a = Convert.ToDouble(Console.ReadLine());

        Console.Write("Введите оператор (+, -, *, /): ");
        string op = Console.ReadLine().Trim();

        Console.Write("Введите второе число: ");
        double b = Convert.ToDouble(Console.ReadLine());

        double result = op switch
        {
            "+" => a + b,
            "-" => a - b,
            "*" => a * b,
            "/" => b != 0 ? a / b : double.NaN,
            _ => double.NaN
        };

        if (double.IsNaN(result))
            Console.WriteLine("Ошибка: некорректный оператор или деление на ноль");
        else
            Console.WriteLine($"{a} {op} {b} = {result}");
    }
}
💡 Обрати внимание: внутри switch-выражения мы используем тернарный оператор для проверки деления на ноль. Никто не запрещает комбинировать разные конструкции!
🧪

Мини-тест

Проверь свои знания о switch.

Вопрос 1

int x = 2;
switch (x)
{
    case 1:
        Console.Write("A ");
    case 2:
        Console.Write("B ");
    case 3:
        Console.Write("C ");
        break;
}

Варианты: A) Ошибка компиляции   B) B C   C) A B C

Вопрос 2

string result = 5 switch
{
    1 => "A",
    2 => "B",
    _ => "C"
};
Console.WriteLine(result);

Варианты: A) A   B) B   C) C

Вопрос 3

object obj = "hello";
string desc = obj switch
{
    int => "число",
    string => "строка",
    _ => "другое"
};
Console.WriteLine(desc);

Варианты: A) число   B) строка   C) другое

Вопрос 4

int code = 404;
string message = code switch
{
    200 => "OK",
    404 => "Not Found",
    500 => "Server Error"
};
Console.WriteLine(message);

Варианты: A) OK   B) Not Found   C) Ошибка компиляции (нет _)

💡 Ответы: 1 — A (case 1 не имеет break, но у него нет кода — ошибка. Только пустые case можно объединять). 2 — C (5 не равно 1 или 2, идёт в _). 3 — B (тип "hello" — string). 4 — C (switch-выражение должно покрывать все возможные значения; int может быть любым, нужен _).
🎮

Задача

Задание: Конвертер валют

Напиши программу-конвертер валют. Пользователь вводит сумму в рублях и выбирает целевую валюту. Используй switch-выражение для выбора курса.

Валюты и курсы (условные):

  • USD — 0.011 (доллар США)
  • EUR — 0.010 (евро)
  • CNY — 0.079 (юань)
  • KZT — 5.20 (тенге)
  • TRY — 0.32 (лира)

Дополнительно:

  • Если валюта не поддерживается — выведи сообщение об ошибке
  • Сумму на выходе округли до 2 знаков после запятой

Пример работы:

Сумма в рублях: 5000
Валюта (USD, EUR, CNY, KZT, TRY): USD
5000 RUB = 55.00 USD
💡 Подсказка: switch-выражение с string идеально подходит. Не забудь про _ для неизвестной валюты. Используй Convert.ToDouble() для ввода.
📌

Что важно запомнить

1️⃣
Switch проверяет на равенство (==) с константами. Для диапазонов и сложных условий — if-else if.
2️⃣
Каждый case должен заканчиваться break, return или throw. Пустые case можно объединять: case 1: case 2:
3️⃣
default — аналог else. Добавляй его всегда для обработки неожиданных значений.
4️⃣
Pattern matching (C# 7+) — switch с типами и условием when. Switch-выражение (C# 8+) — компактный switch, возвращающий значение.
5️⃣
Switch-выражение должно быть исчерпывающим. Если проверяешь int или string — обязательно добавляй _ (discard).

Тест: 3.6: Оператор switch

5 вопросов

Калькулятор

Premium