Перейти к основному содержимому

Управляющие конструкции и логические операторы

Как выбирать конструкцию управления

Короткое правило выбора:

  • if - 1-2 условия с простой логикой;
  • switch - много веток по одному выражению;
  • for - нужен индекс или известно число итераций;
  • foreach - безопасный перебор коллекции;
  • while - число итераций заранее неизвестно;
  • do…while - минимум один проход тела.

Обобщённая шпаргалка — Циклы.


Разбор частых ошибок в условиях

// Плохо: сложное условие в одну строку
if (user != null && user.IsActive && user.Role == "Admin" && user.LastLogin > DateTime.UtcNow.AddDays(-30))
{
// ...
}

Лучше вынести в отдельные булевы переменные:

bool isNotNull = user != null;
bool isActive = isNotNull && user.IsActive;
bool isAdmin = isNotNull && user.Role == "Admin";
bool isRecent = isNotNull && user.LastLogin > DateTime.UtcNow.AddDays(-30);

if (isActive && isAdmin && isRecent)
{
// ...
}

Так код проще читать и тестировать.


Практика для циклов

  • Если внутри цикла есть работа с БД/сетью, проверяйте, не лучше ли батч-обработка.
  • Для раннего выхода используйте break, но фиксируйте причину комментарием.
  • Не меняйте коллекцию внутри foreach, если не уверены в последствиях.

Смежные статьи

Управляющие конструкции и логические операторы

Разработчику Архитектору

Перед чтением: Операторы — общие понятия оператора, операнда, приоритетов и типов операций без привязки к языку.

Сначала: Циклы в коде — общая идея повторений, виды циклов и типичные ошибки без привязки к синтаксису языка.


C# — условия, циклы, операторы

Ветвление — if / else, с C# 9+ часто switch по образцу (не только константы). Циклы — for, foreach, while, do-while; для коллекций и IEnumerableforeach. Логика короткого замыкания: && и || не вычисляют правую часть, если результат уже ясен.

Оператор — символ или ключевое слово над операндами (+, ==, ??). Управляющая конструкция меняет порядок выполнения (if, for, return).

К ним относятся:

  • Условные операторы (if, switch);
  • Циклы (for, while, foreach);
  • Операторы перехода (break, continue, return, goto).

Они позволяют программе "думать" — принимать решения, повторять действия, выходить из блоков и т.д.

Условная операция — это выражение, которое возвращает разные значения в зависимости от условия.

Самый известный пример — тернарный оператор ? :, который является сокращённой формой if-else.

string result = (age >= 18) ? "Доступ разрешён" : "Доступ запрещён";

Разбор:

  • Тернарный оператор ?: выбирает одно из двух значений по булевому условию.
  • Сначала вычисляется age >= 18.
  • Если условие истинно, в result попадёт строка "Доступ разрешён", иначе "Доступ запрещён".
  • Это компактная альтернатива короткому if/else.

Условные операции позволяют писать лаконичный код без развёрнутых блоков if-else.


Операторы

Play ITЗагрузка интерактивного демо…

Операторы делятся на категории по функциональности.


Арифтетические операторы

Арифметические операторы используются для математических вычислений:

ОператорОписаниеПример
+Сложениеint sum = a + b;
-Вычитаниеint diff = a - b;
*Умножениеint product = a * b;
/Делениеint quotient = a / b;
%Остаток от деленияint remainder = a % b;

При делении целых чисел результат усекается: 5 / 2 = 2, а не 2.5


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

Операторы присваивания присваивают значение переменной или изменяют его:

ОператорПримерАналог
=x = 5;нет
+=x += 3;x = x + 3;
-=x -= 3;x = x - 3;
*=x *= 3;x = x * 3;
/=x /= 3;x = x / 3;
%=x %= 3;x = x % 3;

Такие операторы могут быть составными (комбинируют операцию и присваивание).


Инкремент и декремент

Увеличение и уменьшение значения (++, --) изменяют на 1. Это соответственно инкремент и декремент: ++ увеличивает на 1, x++ или ++x; -- уменьшает на 1, x-- или --x.

Как обычно, имеется разница между постфиксной и префиксной формами:

int a = 5;
int b = a++; // b = 5, a = 6 (сначала присвоили, потом увеличили)
int c = ++a; // c = 7, a = 7 (сначала увеличили, потом присвоили)

Разбор:

  • a++ — постфиксный инкремент: возвращает старое значение, затем увеличивает переменную.
  • ++a — префиксный инкремент: сначала увеличивает, затем возвращает новое значение.
  • Поэтому b получает 5, а c7.
  • Разница особенно важна, когда инкремент участвует в присваивании или выражениях.

Сравнение

Операторы сравнения возвращают true или false. Используются в условиях.

ОператорОписаниеПример
==Равноif (a == b)
!=Не равноif (a != b)
>Большеif (a > b)
<Меньшеif (a < b)
>=Больше или равноif (a >= b)
<=Меньше или равноif (a <= b)

Для сравнения содержимого объектов также можно использовать метод .Equals()

string a = "hello";
string b = "hello";
bool isEqual = a.Equals(b); // true

Разбор:

  • Создаются две строковые переменные с одинаковым текстом.
  • a.Equals(b) сравнивает содержимое строк, а не только ссылку.
  • Для одинаковых символов результат будет true.
  • Такой способ явно показывает намерение сравнить значения.

Как можно понять из перевода с английского, equal это равенство, поэтому это сравнение.

Обратите внимание на важную вещь - больше или равно пишется именно >=, а не =>, ведь => это стрелка.


Логические операторы

Логические операторы используются для объединения или инвертирования условий:

ОператорОписаниеПример
&&Логическое Иif (age > 18 && age < 60)
!Логическое НЕif (!isAuthorized)
??Оператор объединения со значением по умолчанию (null-coalescing)string displayName = name ?? "Guest";

Самый распространённый пример применения это !имя, означающий НЕимя, буквально.

В C# есть дополнительный оператор ?? (null-coalescing), который возвращает первый операнд, если он не null, иначе второй.

string name = null;
string displayName = name ?? "Гость"; // "Гость"

Разбор:

  • Оператор ?? возвращает левое значение, если оно не null.
  • Так как name == null, берётся правая часть — "Гость".
  • Это сокращает шаблонные проверки на null.
  • Часто используется для задания безопасных значений по умолчанию.

Это полезно для безопасной работы с nullable-значениями.


is и as

Операторы is (проверка типа объекта) и as (безопасное приведение объекта).

object obj = "Hello";
string str = obj as string;

if (obj is string)
{
Console.WriteLine("Это строка");
}

Разбор:

  • obj объявлен как object, но фактически содержит строку.
  • as string пытается безопасно привести тип: вернёт строку или null.
  • obj is string проверяет совместимость объекта с типом string.
  • При успешной проверке выполняется вывод в консоль.

nameof

Оператор nameof возвращает имя переменной, типа или члена в виде строки:

string paramName = nameof(age); // "age"
Console.WriteLine($"Ошибка в параметре: {paramName}");

Разбор:

  • nameof(age) возвращает имя символа как строку ("age").
  • Это уменьшает риск опечаток в "магических строках".
  • При переименовании переменной IDE обновит nameof автоматически.
  • Интерполяция $"..." вставляет значение paramName в сообщение.

Это удобно для сообщений об ошибках, логирования, когда надо вывести имя чего-то.


Лямбда-оператор

Лямбда-оператор => используется для определения лямбда-выражений:

Func<int, int> square = x => x * x;
Console.WriteLine(square(5)); // 25

// В LINQ
var even = numbers.Where(x => x % 2 == 0);

Разбор:

  • Func<int, int> описывает функцию: принимает int и возвращает int.
  • Лямбда x => x * x вычисляет квадрат переданного числа.
  • Вызов square(5) возвращает 25.
  • В Where(...) лямбда играет роль фильтра: остаются элементы, где x % 2 == 0.

Функции-операторы

Как и в Java, в C# есть методы, которые выполняют функции, аналогичные операторам:

  • .Equals() — аналог оператора == для сравнения содержимого объектов;
  • .CompareTo() — аналог операторов сравнения (<, >, <=, >=);
  • Math класс — аналоги арифметических операций с проверкой на переполнение - Math.Add(), Math.Subtract(), Math.Multiply();
  • BitOperations класс — аналоги битовых операций - BitOperations.PopCount() — подсчитывает количество единиц в двоичном представлении числа;
  • Convert класс — аналоги операторов приведения типов - Convert.ToInt32(), Convert.ToDouble();
  • Object.ReferenceEquals() — проверяет, ссылаются ли два объекта на один и тот же экземпляр (аналог == для ссылок).

Приоритеты выполнения

Операторы выполняются в определённом порядке. Вот основные уровни (от высшего к низшему):

  1. x++, x-- (постфикс);
  2. ++x, --x (префикс), !, (type);
  3. *, /, %;
  4. +, -;
  5. <, >, <=, >=;
  6. ==, !=;
  7. &&;
  8. `;
  9. ?:
  10. =, +=, -= и прочие.

Циклы

Интерактивное демо — пошаговый цикл на примере JavaScript (for, while). В C# синтаксис другой (for, while, foreach), но порядок шагов тот же. Обобщённо: циклы в коде.

Play ITЗагрузка интерактивного демо…

Циклы позволяют выполнять блок кода несколько раз, пока выполняется определённое условие.

КонструкцияПорядокКогда удобна
forинициализация → проверка → тело → шагизвестно число повторений или нужен индекс
foreachследующий элемент → телоперебор массива, List, Dictionary
whileпроверка условия → телочисло итераций заранее неизвестно
do…whileтело → проверка условияминимум один проход (меню, повтор ввода)

for

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

for (int i = 0; i < 5; i++) {
Console.WriteLine($"Итерация {i}");
}
Структура:

for (инициализация; условие; шаг) {
// тело цикла
}

Разбор:

  • for включает три части — инициализация, условие продолжения, шаг после итерации.
  • int i = 0 выполняется один раз перед циклом.
  • i < 5 проверяется перед каждым проходом.
  • i++ увеличивает счётчик после каждой итерации.
  • Внутри тела Console.WriteLine выводит текущее значение индекса.

while

while выполняет код, пока условие истинно:

int count = 0;
while (count < 5) {
Console.WriteLine(count);
count++;
}

Разбор:

  • while повторяет блок, пока условие истинно.
  • Счётчик count стартует с нуля и меняется внутри цикла.
  • На каждой итерации выводится текущее значение переменной.
  • count++ нужен для прогресса; без изменения условия возможен бесконечный цикл.

Структура:

while (условие) {
//тело цикла
}

Разбор:

  • Это базовый шаблон цикла while.
  • Условие проверяется перед каждой итерацией.
  • Если условие изначально ложно, тело не выполнится ни разу.
  • Обычно внутри изменяют состояние, влияющее на условие завершения.

do...while

do…while выполняет код хотя бы один раз, затем проверяет условие:

int number;
do {
Console.Write("Введите число больше 0: ");
number = int.Parse(Console.ReadLine());
} while (number <= 0);

Разбор:

  • do...while гарантирует хотя бы одно выполнение тела цикла.
  • Сначала пользователь вводит значение, потом проверяется условие повторения.
  • int.Parse(...) преобразует строку в число.
  • Цикл продолжается, пока введено значение <= 0.

Структура:

do {
//тело цикла
} while (условие)

Разбор:

  • Это шаблон do...while: "выполнить, затем проверить".
  • Отличие от while — первая итерация всегда выполняется.
  • Удобно для меню, повторного ввода и сценариев с обязательным первым действием.
  • После while (условие) в C# должна стоять точка с запятой.

foreach

foreach, перебор коллекций, удобен для массивов, списков, словарей и других перечисляемых типов:

string[] names = { "Alice", "Bob", "Charlie" };
foreach (string name in names) {
Console.WriteLine(name);
}

Разбор:

  • string[] создаёт массив строк.
  • foreach проходит по каждому элементу коллекции без индекса.
  • На каждой итерации текущий элемент попадает в переменную name.
  • Это безопасный и читаемый способ перебора, когда индекс не нужен.

Структура:

foreach(тип переменная in коллекция) {
//тело цикла
}

Разбор:

  • Шаблон показывает общий синтаксис foreach.
  • коллекция должна быть перечисляемой (IEnumerable).
  • переменная имеет тип элемента коллекции.
  • Подходит для массива, списка, словаря и других перечисляемых структур.

Управление циклом

Существуют специальные управляющие операторы - break, continue, goto.

Циклы прерываются через ключевое слово break, а продолжаются через continue (переход к следующей итерации). Пример:

for (int i = 0; i < 10; i++) {
if (i == 5) break; // остановится на 5
if (i % 2 == 0) continue; // пропустит чётные числа
Console.WriteLine(i);
}

Разбор:

  • Цикл идёт по значениям 0..9.
  • break полностью завершает цикл при i == 5.
  • continue пропускает текущую итерацию для чётных чисел.
  • В консоль выведутся только нечётные значения до пяти: 1 и 3.

В чем разница между "Break" и "Continue" в C#?

break: используется в циклах (for и т. д.) и операторах переключения, завершает итерацию/переключение и пропускает весь оставшийся код в цикле или блоке переключения.

continue: используется только в циклах, пропускает весь оставшийся код в цикле и начинает следующую итерацию с начала цикла.

И есть ещё goto - переход к метке. Он редко используется и может усложнить код. Чаще всего его заменяют нормальными управляющими конструкциями.