1. Вступ
Ви вже вмієте писати такий код:
switch (color)
{
case "red":
Console.WriteLine("Стоп!");
break;
case "yellow":
Console.WriteLine("Чекайте...");
break;
case "green":
Console.WriteLine("Можна йти!");
break;
default:
Console.WriteLine("А це що за колір?");
break;
}
Але що, якщо ми хочемо надавати змінній різні значення залежно від вхідного параметра — наприклад, повертати з функції рядок, що ґрунтується на числі? До появи switch-виразів доводилося писати ось такі конструкції:
string meaning;
switch (number)
{
case 42:
meaning = "Відповідь на головне питання життя, всесвіту і взагалі всього";
break;
case 7:
meaning = "Щасливе число";
break;
default:
meaning = "Звичайне число";
break;
}
Не надто елегантно для мови XXI століття, чи не так? Хочеться одразу повернути значення, як це зазвичай буває у функціональних мовах.
Саме тут і зʼявляються switch-вирази — одна з найкрасивіших (і свіжих) можливостей C#, починаючи з версії 8.0.
2. switch-вирази: синтаксис, яким приємно користуватися
Порівняймо: оператор і вираз
Класичний switch — це statement («оператор»), а switch-вираз — expression («вираз»): він обчислює значення, яке можна одразу присвоїти змінній або повернути з методу.
Структура switch-виразу:
var result = value switch
{
pattern1 => expression1,
pattern2 => expression2,
_ => defaultExpression // "_" це "інакше"
};
Наприклад:
int number = 42;
string meaning = number switch
{
42 => "Відповідь на головне питання життя, всесвіту і взагалі всього",
7 => "Щасливе число",
_ => "Звичайне число"
};
Console.WriteLine(meaning); // => Відповідь на головне питання життя, всесвіту і взагалі всього
Усе лаконічно й читабельно: жодного break; і жодних громіздких конструкцій.
Зверніть увагу: підкреслення _ — це «усі інші випадки», аналог default.
3. switch-вирази і патерни: як вони поєднуються
Ось де починається найцікавіше. У switch-виразах можна використовувати не лише звичайні значення, а й патерни: перевірки за діапазоном, типом, властивостями об’єктів, деконструкції (розбиття об’єкта на частини) і навіть combinatorial patterns (and, or, not).
Приклади патернів у switch-виразі
Константні патерни
Це те, що ми вище вже робили: порівняння з 42, 7 і так далі.
Діапазони та порівняння
int age = 17;
string category = age switch
{
< 18 => "Неповнолітній",
>= 18 and <= 65 => "Дорослий",
> 65 => "Літня людина",
_ => "Невідома вікова категорія"
};
Console.WriteLine(category);
До речі, зверніть увагу: можна поєднувати кілька умов. C# стає дедалі виразнішим.
Типові патерни (Type Patterns)
Припустімо, у нас є об’єкт, який може мати різний тип (наприклад, object value;). Можемо обробити їх так:
object value = 3.14;
string description = value switch
{
int i => $"Ціле число: {i}",
double d => $"Дробове число: {d:F2}",
string s => $"Це рядок: '{s}'",
null => "null!",
_ => "Щось інше"
};
Console.WriteLine(description); // => Дробове число: 3.14
Пов’язані патерни (Property Patterns і Positional Patterns)
Починаючи з C# 8, можна перевіряти значення властивостей прямо у switch-виразі.
Приклад з об’єктом
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
User user = new User { Name = "Анна", Age = 17 };
string welcome = user switch
{
{ Age: < 18 } => $"Вітаємо, {user.Name}! Ви підліток.",
{ Age: >= 18 and <= 65 } => $"Вітаємо, {user.Name}! Доросле життя чудове.",
{ Age: > 65 } => $"Ласкаво просимо, {user.Name}! Вам завжди раді.",
_ => "Невідомий вік"
};
Console.WriteLine(welcome);
У фігурних дужках { Age: < 18 } — це property pattern: ми перевіряємо не весь об’єкт, а лише його властивість.
4. Нові патерни C# 11-14
C# прагне до лаконічності та гнучкості. Нещодавно в ньому з’явилися combinatorial patterns: and, or, not, а також удосконалено positional patterns. Розгляньмо їх.
Логічні патерни: and, or, not
Ви можете створювати складні умови, як у математичній логіці.
int temperature = 25;
string result = temperature switch
{
< 0 => "Мороз!",
>= 0 and < 20 => "Прохолодно",
>= 20 and < 30 => "Комфортно",
>= 30 or <= -30 => "Екстрим!",
_ => "Дивна температура"
};
Щоб виключити певні випадки:
int score = 80;
string grade = score switch
{
>= 90 => "Відмінно",
>= 60 and not >= 90 => "Добре",
_ => "Погано"
};
Деконструкція (Positional Patterns)
Якщо у вас структура або record, який підтримує деконструкцію, C# дозволяє розбивати об’єкт прямо у switch-виразі:
public record Point(int X, int Y);
Point p = new Point(10, 20);
string desc = p switch
{
(0, 0) => "Початок координат",
(var x, 0) => $"На осі X, X={x}",
(0, var y) => $"На осі Y, Y={y}",
(var x, var y) when x == y => $"На діагоналі: {x}",
_ => $"У точці ({p.X}, {p.Y})"
};
Console.WriteLine(desc); // => У точці (10, 20)
5. Коли і навіщо використовувати switch-вирази
У сучасному C# switch-вирази — це не просто модна можливість, а дієвий спосіб уникнути зайвого коду, зробити його компактнішим, легшим для тестування й підтримки. Це особливо важливо під час написання парсерів, обробників команд, бізнес-логіки, конфігурування правил — скрізь, де потрібно розгалужувати виконання за складними критеріями: не лише за значеннями, а й за типами, діапазонами, властивостями та їх комбінаціями.
На співбесідах
- Як би ви обробили різні варіанти відповіді від користувача?
- Як зробити так, щоб повернути різне значення функції, яке залежить і від типу, і від значення?
- Як ви легко додаватимете нові правила без купи if-else?
Покажіть switch-вираз із патернами! Це відразу продемонструє ваші знання нових можливостей мови й добрий стиль кодування.
Таблиця: порівняння switch-оператора і switch-виразу
| Характеристика | switch statement | switch expression |
|---|---|---|
| Тип | оператор (statement) | вираз (expression) |
| Використання break | обов’язково | не потрібен |
| Може повертати значення | лише через змінну | так, прямо повертає значення |
| Може використовувати патерни | частково | повністю (type, property тощо) |
| Пастка | можна забути break | усі шляхи мають повертати значення |
6. Типові помилки й підводні камені
- Початківці часто плутають різницю між switch-оператором («statement») і switch-виразом («expression»). Наприклад, забувають, що у switch-виразі не потрібні break;, а всі гілки обов’язково мають повертати значення.
- Якщо забути гілку _, компілятор підкаже: «А якщо нічого не підійшло?».
- У switch-виразі не можна використовувати goto (і це на краще).
- Якщо дублюється умова (наприклад, два однакових патерни), компілятор це теж не пропустить.
- Уважно ставтеся до типу значення, що повертається з switch-виразу: він має бути сумісний із типом змінної, куди ви це присвоюєте.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ