C#
Операторы ветвления

Операторы ветвления

Условные конструкции - один из базовых компонентов многих языков программирования, которые направляют работу программы по одному из путей в зависимости от определенных условий.

if .. else

Конструкция if else проверяет истинность некоторого условия и в зависимости от результатов проверки выполняет определенный код.

Ее простейшая форма состоит из блока if:

if(условие)
{
    выполняемые инструкции
}

После ключевого слова if ставится условие. Условие должно представлять значение типа bool. Это может быть непосредственно значение типа bool или результат условного выражения или другого выражения, которое возвращает значение типа bool. И если это условие истинно (равно true), то срабатывает код, который помещен далее после условия внутри фигурных скобок.

Например:

int num1 = 8;
int num2 = 6;
if(num1 > num2)
{
    Console.WriteLine($"Число {num1} больше числа {num2}");
}

В данном случае у нас первое число больше второго, поэтому выражение num1 > num2 истинно и возвращает true, следовательно, управление переходит к строке Console.WriteLine("Число {num1} больше числа {num2}");

Если блок if содержит одну инструкцию, то мы можем его сократить, убрав фигурные скобки:

int num1 = 8;
int num2 = 6;
if (num1 > num2)
    Console.WriteLine($"Число {num1} больше числа {num2}");
 
// или так
if (num1 > num2) Console.WriteLine($"Число {num1} больше числа {num2}");

Также мы можем соединить сразу несколько условий, используя логические операторы:

int num1 = 8;
int num2 = 6;
if(num1 > num2 && num1==8)
{
    Console.WriteLine($"Число {num1} больше числа {num2}");
}

В данном случае блок if будет выполняться, если num1 > num2 равно true и num1==8 равно true.

else

Но что, если мы захотим, чтобы при несоблюдении условия также выполнялись какие-либо действия? В этом случае мы можем добавить блок else:

int num1 = 8;
int num2 = 6;
if(num1 > num2)
{
    Console.WriteLine($"Число {num1} больше числа {num2}");
}
else
{
    Console.WriteLine($"Число {num1} меньше числа {num2}");
}

Блок else выполняется, если условие после if ложно, то есть равно false.

Если блок else содержит только одну инструкцию, то опять же мы можем его сократить, убрав фигурные скобки:

int num1 = 8;
int num2 = 6;
if(num1 > num2)
    Console.WriteLine($"Число {num1} больше числа {num2}");
else
    Console.WriteLine($"Число {num1} меньше числа {num2}");

else if

Но в примере выше при сравнении чисел мы можем насчитать три состояния: первое число больше второго, первое число меньше второго и числа равны. Используя конструкцию else if, мы можем обрабатывать дополнительные условия:

int num1 = 8;
int num2 = 6;
if(num1 > num2)
{
    Console.WriteLine($"Число {num1} больше числа {num2}");
}
else if (num1 < num2)
{
    Console.WriteLine($"Число {num1} меньше числа {num2}");
}
else
{
    Console.WriteLine("Число num1 равно числу num2");
}

При необходимости можно добавить несколько выражений else if:

string name = "Alex";
 
if (name == "Tom")
    Console.WriteLine("Вас зовут Tomas");
else if (name == "Bob")
    Console.WriteLine("Вас зовут Robert");
else if (name == "Mike")
    Console.WriteLine("Вас зовут Michael");
else
    Console.WriteLine("Неизвестное имя");

Тернарная операция

Тернарная операция также позволяет проверить некоторое условие и в зависимости от его истинности выполнить некоторые действия. Она имеет следующий синтаксис:

[первый операнд - условие] ? [второй операнд] : [третий операнд]

Здесь сразу три операнда. В зависимости от условия тернарная операция возвращает второй или третий операнд: если условие равно true, то возвращается второй операнд; если условие равно false, то третий.

Например:

int x=3;
int y=2;
 
int z = x < y ? (x+y) : (x-y);
Console.WriteLine(z);   // 1

Здесь первый операнд (то есть условие) представляет выражение x < y. Если оно равно true, то возвращается второй операнд - (x+y), то есть результат операции сложения. Если условие равно false, то возвращается третий операнд - (x-y).

Результат тернарной операции (то есть второй или третий операнд в зависимости от условия) присваивается переменной z.

switch

Конструкция switch case оценивает некоторое выражение и сравнивает его значение с набором значений. И при совпадении значений выполняет определенный код.

Конструкция switch имеет следующее формальное определение:

switch (выражение)
{
    case значение1:
        код,выполняемый если выражение имеет значение1
        break;
    case значение2:
        код,выполняемый если выражение имеет значение2
        break;
    //.............
    case значениеN:
        код, выполняемый если выражение имеет значениеN
        break;
    default:
        код, выполняемый если выражение не имеет ни одно из выше указанных значений
        break;
}

После ключевого слова switch в скобках идет сравниваемое выражение. Значение этого выражения последовательно сравнивается со значениями, помещенными после оператора case. И если совпадение будет найдено, то будет выполняться определенный блок case.

В конце каждого блока case должен ставиться один из операторов перехода: break, goto case, return или throw. Как правило, используется оператор break. При его применении другие блоки case выполняться не будут.

Например:

string name = "Tom";
 
switch (name)
{
    case "Bob":
        Console.WriteLine("Ваше имя - Bob");
        break;
    case "Tom":
        Console.WriteLine("Ваше имя - Tom");
        break;
    case "Sam":
        Console.WriteLine("Ваше имя - Sam");
        break;
}

В данном случае конструкция switch последовательно сравнивает значение переменной name с набором значений, которые указаны после операторов case. Поскольку здесь значение переменной name - строка "Tom", то будет выполняться блок

case "Tom":
    Console.WriteLine("Ваше имя - Tom");
    break;

Соответственно мы увидим на консоли:

Ваше имя - Tom

Если значение переменной name не совпадает ни с каким значением после операторов case, то ни один из блоков case не выполняется. Однако если даже в этом случае нам все равно надо выполнить какие-нибудь действия, то мы можем добавить в конструкцию switch необязательный блок default. Например:

string name = "Alex";
 
switch (name)
{
    case "Bob":
        Console.WriteLine("Ваше имя - Bob");
        break;
    case "Tom":
        Console.WriteLine("Ваше имя - Tom");
        break;
    case "Sam":
        Console.WriteLine("Ваше имя - Sam");
        break;
    default:
        Console.WriteLine("Неизвестное имя");
        break;
}

В данном случае никакое из значений после операторов case не совпадает со значением переменной name, поэтому будет выполняться блок default:

default:
    Console.WriteLine("Неизвестное имя");
    break;

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

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 позволяет возвращать некоторое значение. Для возвращения значения в блоках case может применятся оператор return. Например, определим следующий метод:

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.

Естественно, мы можем сразу возвратить из метода результат без присвоения переменной результата конструкции switch:

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 или какое-то другое? Поэтому данная версия метода даже не скомпилируется. Поэтому нам надо предусмотреть возвращение значения из метода при всех возможных вариантах. То есть, мы можем, как в примере выше, добавить в конструкцию switch блок default, в котором будет возвращаться значение при всех остальных случаях.