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

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

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

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

Все программы управляются с помощью операторов и циклов, которые позволяют:

  • принимать решения (условные операторы);
  • выполнять повторяющиеся действия (циклы);
  • манипулировать данными (арифметические, логические, сравнительные операторы).

Оператор (operator) — это символ или ключевое слово, которое выполняет операцию над одним или несколькими значениями (операндами).

Операторы используются для:

  • Манипуляции данными;
  • Сравнения значений;
  • Управления потоком выполнения программы.

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

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

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

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

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

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

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

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

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

  1. Арифметические операторы используются для математических вычислений:
ОператорОписаниеПример
+Сложение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

  1. Операторы присваивания присваивают значение переменной или изменяют его:
ОператорПримерАналог
=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. Это соответственно инкремент и декремент: ++ увеличивает на 1, x++ или ++x; -- уменьшает на 1, x-- или --x.

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

int a = 5;
int b = a++; // b = 5, a = 6 (сначала присвоили, потом увеличили)
int c = ++a; // c = 7, a = 7 (сначала увеличили, потом присвоили)
  1. Операторы сравнения возвращают 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

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

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

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

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

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

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

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

  1. Операторы is (проверка типа объекта) и as (безопасное приведение объекта).
object obj = "Hello";
string str = obj as string;

if (obj is string)
{
Console.WriteLine("Это строка");
}
  1. Оператор nameof возвращает имя переменной, типа или члена в виде строки:
string paramName = nameof(age); // "age"
Console.WriteLine($"Ошибка в параметре: {paramName}");

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

  1. Лямбда-оператор => используется для определения лямбда-выражений:
Func<int, int> square = x => x * x;
Console.WriteLine(square(5)); // 25

// В LINQ
var even = numbers.Where(x => 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. =, +=, -= и прочие.

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

  1. for это цикл со счётчиком, который используется, когда известно количество итераций:
for (int i = 0; i < 5; i++) {
Console.WriteLine($"Итерация {i}");
}
Структура:

for (инициализация; условие; шаг) {
// тело цикла
}
  1. while выполняет код, пока условие истинно:
int count = 0;
while (count < 5) {
Console.WriteLine(count);
count++;
}

Структура:

while (условие) {
//тело цикла
}
  1. do…while выполняет код хотя бы один раз, затем проверяет условие:
int number;
do {
Console.Write("Введите число больше 0: ");
number = int.Parse(Console.ReadLine());
} while (number <= 0);

Структура:

do {
//тело цикла
} while (условие)
  1. foreach, перебор коллекций, удобен для массивов, списков, словарей и других перечисляемых типов:
string[] names = { "Alice", "Bob", "Charlie" };
foreach (string name in names) {
Console.WriteLine(name);
}

Структура:

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

Существуют специальные управляющие операторы - 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);
}

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

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

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

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