This lesson is not translated yet – the Russian original is below.
Пока программа выполняет строки подряд, она умеет ровно одно – то, что записано. Ветвление даёт ей выбор: сделать так или иначе, в зависимости от данных.
if и else
int age = 20;
if (age >= 18)
{
Console.WriteLine("Совершеннолетний");
}
else
{
Console.WriteLine("Несовершеннолетний");
}
В скобках после if – условие, выражение типа bool. Не число, не строка, не объект: только
истина или ложь.
В C и JavaScript условием может быть что угодно: ноль – ложь, непустая строка – истина. В C# так нельзя, и это к лучшему. Опечатка if (x = 5), годами кормившая отладчики в других языках, здесь просто не соберётся.
Когда веток больше двух, их выстраивают цепочкой:
if (score >= 90)
{
Console.WriteLine("отлично");
}
else if (score >= 75)
{
Console.WriteLine("хорошо");
}
else if (score >= 60)
{
Console.WriteLine("удовлетворительно");
}
else
{
Console.WriteLine("неудовлетворительно");
}
Проверки идут сверху вниз, и первая подошедшая выигрывает – остальные даже не вычисляются.
Поэтому во второй ветке не нужно писать score >= 75 && score < 90: если бы значение было
больше 90, до сюда бы не дошли.
Операторы сравнения
| Оператор | Значение |
|---|---|
== |
равно |
!= |
не равно |
> < |
больше, меньше |
>= <= |
больше или равно, меньше или равно |
Двойное равенство – это сравнение, одинарное – присваивание. Перепутать в условии не выйдет:
компилятор сообщит, что не может преобразовать int в bool.
Для дробных чисел == ненадёжен – см. урок про точность. Для строк работает нормально: == сравнивает содержимое, а не адреса, потому что для string это поведение переопределено специально.
Логические операторы
| Оператор | Название | Истинно, когда |
|---|---|---|
&& |
и | истинны обе части |
|| |
или | истинна хотя бы одна |
! |
не | часть ложна |
if (age >= 18 && hasPassport)
{
Console.WriteLine("Можно оформлять");
}
if (day == 6 || day == 7)
{
Console.WriteLine("Выходной");
}
if (!isBlocked)
{
Console.WriteLine("Доступ открыт");
}
Отрицание читается тяжелее, чем утверждение, поэтому if (!isBlocked) лучше, чем
if (isBlocked == false), но ещё лучше – назвать переменную так, чтобы отрицание не
требовалось: isAllowed.
Короткое замыкание
&& и || вычисляют правую часть только при необходимости:
- в
a && b: еслиaложно, результат уже ложь –bне вычисляется; - в
a || b: еслиaистинно, результат уже истина –bне вычисляется.
Это не оптимизация, а рабочий приём. На нём строится защита от null:
if (text != null && text.Length > 0)
{
Console.WriteLine(text);
}
Поменяйте проверки местами – получите NullReferenceException: text.Length вычислится раньше,
чем проверка на null.
Есть ещё & и | – они всегда вычисляют обе части. В условиях они почти не нужны, зато нужны при работе с битами. Если увидели одиночный знак в if, чаще всего это опечатка.
Фигурные скобки
Для одной инструкции скобки формально не обязательны:
if (age >= 18)
Console.WriteLine("Совершеннолетний");
Так писать не стоит. Когда через месяц в ветку добавляют вторую строку, отступ создаёт иллюзию, что она тоже внутри условия, – а она снаружи:
if (age >= 18)
Console.WriteLine("Совершеннолетний");
Console.WriteLine("Доступ открыт"); // выполнится всегда
Ошибка невидима глазами и стоила индустрии дорого: в 2014 году именно такая пара строк без скобок в коде Apple обернулась уязвимостью в проверке SSL-сертификатов.
Ставьте скобки всегда, даже ради одной строки. Это соглашение по умолчанию почти во всех командах, и спорить с ним себе дороже.
Тернарный оператор
Когда обе ветки просто дают значение, тремя строчками писать не обязательно:
string status = age >= 18 ? "взрослый" : "ребёнок";
Читается как вопрос: условие, потом ?, потом ответ «да», потом :, потом ответ «нет».
Тернарный оператор хорош для короткого выбора значения и плох для всего остального. Вложенные тернарники превращаются в ребус:
string result = a > b ? a > c ? "a" : "c" : b > c ? "b" : "c"; // так не надо
Условия внутри интерполяции
Мелочь, которая экономит промежуточную переменную:
Console.WriteLine($"Товаров: {count} {(count == 1 ? "штука" : "штук")}");
Внутренние скобки обязательны: без них двоеточие тернарного оператора будет принято за начало формата вывода, и компилятор запутается.