Перейти до основного вмісту

Конструкція switch

Конструкція switch/case оцінює деякий вираз і порівнює його значення з набором значень. І якщо значення співпадають, вона виконує певний код...:

Конструкція switch має наступне формальне визначення:

switch (expression)
{
case value1:
code executed if expression has value1
break;
case value2:
code to be executed if the expression has value2
break;
//.............
case valueN:
code to be executed if the expression has valueN
break;
default:
code executed if the expression has none of the above values
break;
}

За ключовим словом switch в дужках слідує вираз, який потрібно порівняти. Значення цього виразу послідовно порівнюється зі значеннями, розміщеними після оператора case. І якщо знайдено співпадіння, виконується певний блок case.

Наприкінці кожного блоку case повинен бути розміщений один з операторів переходу: break, goto case або return. Як правило, використовується оператор break. Коли він використовується, інші блоки case не будуть виконуватися.

Наприклад:

string name = "Tom";

switch (name)
{
case "Bob":
Console.WriteLine("Your name is Bob");
break;
case "Tom":
Console.WriteLine("Your name is Tom");
break;
case "Sam":
Console.WriteLine("Your name is Sam");
break;
}

У цьому випадку конструкція switch послідовно порівнює значення змінної name з набором значень, вказаних після операторів case. Оскільки тут значення змінної name — рядок "Tom", буде виконано блок

case "Tom":
Console.WriteLine("Your name is Tom");
break;

Відповідно, ми побачимо на консолі

Your name is Tom

Якщо значення змінної name не співпадає з жодним значенням після операторів case, то жоден з блоків case не буде виконано. Однак, якщо навіть у цьому випадку нам все ж потрібно виконати деякі дії, ми можемо додати необов'язковий блок default до конструкції switch. Наприклад:

string name = "Alex";

switch (name)
{
case "Bob":
Console.WriteLine("Your name is Bob");
break;
case "Tom":
Console.WriteLine("Your name is Tom");
break;
case "Sam":
Console.WriteLine("Your name is Sam");
break;
default:
Console.WriteLine("Unknown name");
break;
}

У цьому випадку жодне зі значень після операторів case не співпадає зі значенням змінної name, тому буде виконано блок default:

default:
Console.WriteLine("Unknown name");
break;

Однак, якщо ми хочемо, щоб після поточного блоку case було виконано інший блок case, ми можемо використовувати оператор goto case замість break:

int number = 1;
switch (number)
{
case 1:
Console.WriteLine("case 1");
goto case 5; // перехід до case 5
case 3:
Console.WriteLine("case 3");
break;
case 5:
Console.WriteLine("case 5");
break;
default:
Console.WriteLine("default");
break;
}

Повернення значення з switch

Конструкція switch дозволяє повертати деяке значення. Оператор return можна використовувати для повернення значення в блоках case. Наприклад, визначимо наступний метод:

int DoOperation(int op, int a, int b)
{
switch (op)
{
case 1: return a + b;
case 2: return a - b;
case 3: return a * b;
default: return 0;
}
}

Методу DoOperation() передається числовий код операції та два операнди. Залежно від коду операції, над операндами виконується певна операція, і її результат повертається з методу. Наприклад, метод за замовчуванням повертає 0, якщо код операції не 1, 2 або 3.

Ми можемо викликати метод:

int DoOperation(int op, int a, int b)
{
switch (op)
{
case 1: return a + b;
case 2: return a - b;
case 3: return a * b;
default: return 0;
}
}

int result1 = DoOperation(1, 10, 5); // 15
Console.WriteLine(result1); // 15

int result2 = DoOperation(3, 10, 5); // 50
Console.WriteLine(result2); // 50

Отримання результату з switch

Хоча конструкція switch у наведеному вище прикладі працює добре, ми можемо скоротити її та отримати результат безпосередньо з конструкції switch:

int DoOperation(int op, int a, int b)
{
int result = op switch {
1 => a + b,
2 => a - b,
3 => a * b,
_ => 0
};
return result;
}

Тепер оператор case не потрібен, але після порівнюваного значення ставиться оператор стрілки =>. Значення праворуч від стрілки виступає як значення для повернення. Крім того, замість оператора default використовується символ _ (нижнє підкреслення). В результаті результат конструкції switch буде присвоєно змінній result.

Звичайно, ми можемо повернути результат з методу без присвоєння значення змінній result:

int DoOperation(int op, int a, int b)
{
return op switch
{
1 => a + b,
2 => a - b,
3 => a * b,
_ => 0
};
}

Або зробити метод ще коротшим:

int DoOperation(int op, int a, int b) => op switch
{
1 => a + b,
2 => a - b,
3 => a * b,
_ => 0
};

Зверніть увагу, що це спрощення застосовується лише до конструкцій switch, які повертають деякі значення, як у наведеному вище прикладі.

Варто зазначити, що при поверненні значення з методу, метод повинен повертати значення в будь-якому випадку. Наприклад, наступна версія методу не працюватиме:

int DoOperation(int op, int a, int b)
{
return op switch
{
1 => a + b,
2 => a - b,
3 => a * b
};
}

Ця версія методу повертає значення, якщо код операції 1, 2 або 3. Але що, якщо буде передано значення 4 або якесь інше? Тому ця версія методу навіть не скомпілюється. Отже, нам потрібно передбачити повернення значення з методу у всіх можливих випадках. Тобто ми можемо, як у наведеному вище прикладі, додати блок default до конструкції switch, який повертатиме значення у всіх інших випадках.