Операторы ветвления
Условные конструкции - один из базовых компонентов многих языков программирования, которые направляют работу программы по одному из путей в зависимости от определенных условий.
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
, в котором будет возвращаться значение при всех остальных случаях.