C# 中的控制流
Условия и циклы в C#: if, switch, foreach и LINQ
Представь, что ты пишешь инструкцию для робота-помощника. «Если на улице дождь — возьми зонт, иначе надень солнечные очки. Повтори каждый шаг 10 раз. Для каждого предмета в списке — проверь его.» Именно это делают условия и циклы в программировании — управляют тем, как и когда выполняется код.
Условный оператор if/else
Оператор if — это «развилка на дороге». Программа проверяет условие и выбирает один из путей.
int age = 16;
// Простой if
if (age >= 18)
{
Console.WriteLine("Доступ разрешён");
}
// if с else
if (age >= 18)
{
Console.WriteLine("Взрослый");
}
else
{
Console.WriteLine("Несовершеннолетний");
}
// Цепочка if-else if-else
int score = 75;
if (score >= 90)
{
Console.WriteLine("Отлично! (A)");
}
else if (score >= 75)
{
Console.WriteLine("Хорошо (B)");
}
else if (score >= 60)
{
Console.WriteLine("Удовлетворительно (C)");
}
else
{
Console.WriteLine("Нужно подтянуться (F)");
}
// Результат: Хорошо (B)
Операторы сравнения и логические операторы
int a = 10, b = 5;
// Операторы сравнения
Console.WriteLine(a == b); // false — равно
Console.WriteLine(a != b); // true — не равно
Console.WriteLine(a > b); // true — больше
Console.WriteLine(a < b); // false — меньше
Console.WriteLine(a >= b); // true — больше или равно
Console.WriteLine(a <= b); // false — меньше или равно
// Логические операторы
bool x = true, y = false;
Console.WriteLine(x && y); // false — И (оба должны быть true)
Console.WriteLine(x || y); // true — ИЛИ (хотя бы один true)
Console.WriteLine(!x); // false — НЕ (инверсия)
// Практический пример
int temperature = 25;
bool isSunny = true;
if (temperature > 20 && isSunny)
{
Console.WriteLine("Отличный день для прогулки!");
}
Тернарный оператор: краткая форма if/else
int age = 20;
// Длинная форма
string status;
if (age >= 18)
{
status = "взрослый";
}
else
{
status = "ребёнок";
}
// Краткая форма с тернарным оператором ? :
string status2 = age >= 18 ? "взрослый" : "ребёнок";
Console.WriteLine(status2); // взрослый
// Ещё примеры
int x = 5;
string result = x > 0 ? "положительное" : x < 0 ? "отрицательное" : "ноль";
int max = a > b ? a : b; // Максимум из двух чисел
Оператор switch: много вариантов выбора
Когда вариантов выбора много, цепочка if-else становится громоздкой. Для этого есть оператор switch.
int dayNumber = 3;
// Классический switch
switch (dayNumber)
{
case 1:
Console.WriteLine("Понедельник");
break;
case 2:
Console.WriteLine("Вторник");
break;
case 3:
Console.WriteLine("Среда");
break;
case 4:
Console.WriteLine("Четверг");
break;
case 5:
Console.WriteLine("Пятница");
break;
case 6:
case 7:
Console.WriteLine("Выходной!");
break;
default:
Console.WriteLine("Неверный номер дня");
break;
}
// Результат: Среда
Switch expression: современный синтаксис (C# 8+)
// Новый элегантный switch expression
int dayNumber = 3;
string dayName = dayNumber switch
{
1 => "Понедельник",
2 => "Вторник",
3 => "Среда",
4 => "Четверг",
5 => "Пятница",
6 or 7 => "Выходной",
_ => "Неверный день" // _ это default
};
Console.WriteLine(dayName); // Среда
// Switch с условиями (pattern matching)
int score = 85;
string grade = score switch
{
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
>= 60 => "D",
_ => "F"
};
Console.WriteLine(grade); // B
// Switch по типам
object obj = "Привет";
string description = obj switch
{
int n => $"Число: {n}",
string s => $"Строка длиной {s.Length}",
bool b => $"Булево: {b}",
null => "null",
_ => "Неизвестный тип"
};
Console.WriteLine(description); // Строка длиной 6
Цикл for: точное количество повторений
Цикл for используется, когда знаешь точное количество повторений. Представь: «пробеги 10 кругов» — ты знаешь количество.
// Базовый for: от 1 до 10
for (int i = 1; i <= 10; i++)
{
Console.Write(i + " ");
}
// Результат: 1 2 3 4 5 6 7 8 9 10
Console.WriteLine(); // Перевод строки
// Структура for: (начало; условие продолжения; шаг)
for (int i = 0; i < 5; i++) // Счёт с нуля: 0,1,2,3,4
for (int i = 10; i >= 1; i--) // Обратный счёт: 10,9,...,1
for (int i = 0; i < 20; i += 2) // С шагом 2: 0,2,4,...,18
// Таблица умножения на 5
Console.WriteLine("Таблица умножения на 5:");
for (int i = 1; i <= 10; i++)
{
Console.WriteLine($"5 × {i} = {5 * i}");
}
// Вложенные циклы — таблица умножения 3×3
for (int i = 1; i <= 3; i++)
{
for (int j = 1; j <= 3; j++)
{
Console.Write($"{i * j,3}"); // ,3 — ширина поля 3 символа
}
Console.WriteLine();
}
// Результат:
// 1 2 3
// 2 4 6
// 3 6 9
Цикл while: пока условие истинно
// while — как загрузка: крутится пока не закончит
int health = 100;
int damage = 15;
while (health > 0)
{
Console.WriteLine($"HP: {health}");
health -= damage;
}
Console.WriteLine("Игрок погиб!");
// Ввод с проверкой
Console.Write("Введите число от 1 до 10: ");
int number;
while (!int.TryParse(Console.ReadLine(), out number) || number < 1 || number > 10)
{
Console.Write("Неверный ввод! Попробуй снова: ");
}
Console.WriteLine($"Ты ввёл: {number}");
Цикл do-while: минимум одно выполнение
// do-while выполняется хотя бы один раз
int attempts = 0;
string secret = "C#";
string guess;
do
{
Console.Write("Угадай язык программирования: ");
guess = Console.ReadLine();
attempts++;
} while (guess != secret);
Console.WriteLine($"Правильно! Попыток: {attempts}");
Цикл foreach: для каждого элемента
Самый удобный цикл для работы с коллекциями — массивами, списками и другими наборами данных.
// Массив имён
string[] names = { "Алиса", "Борис", "Василий", "Галина" };
foreach (string name in names)
{
Console.WriteLine($"Привет, {name}!");
}
// Результат:
// Привет, Алиса!
// Привет, Борис!
// Привет, Василий!
// Привет, Галина!
// Список чисел
var numbers = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = 0;
foreach (int num in numbers)
{
sum += num;
}
Console.WriteLine($"Сумма: {sum}"); // 55
// Перебор символов строки
string word = "Привет";
foreach (char c in word)
{
Console.Write(c + "-"); // П-р-и-в-е-т-
}
break и continue: управление циклом
// break — прерывает цикл полностью
Console.WriteLine("Ищем первое число больше 5:");
int[] numbers = { 1, 3, 7, 2, 9, 4 };
foreach (int n in numbers)
{
if (n > 5)
{
Console.WriteLine($"Нашли: {n}");
break; // Выходим из цикла
}
}
// Нашли: 7
// continue — пропускает текущую итерацию
Console.WriteLine("Только чётные числа:");
for (int i = 1; i <= 10; i++)
{
if (i % 2 != 0) continue; // Пропускаем нечётные
Console.Write(i + " ");
}
// 2 4 6 8 10
Введение в LINQ: SQL для коллекций
LINQ (Language Integrated Query — встроенный язык запросов) — это мощный инструмент C# для работы с коллекциями. Представь, что у тебя есть база данных в памяти, и ты можешь делать к ней SQL-запросы прямо в коде!
using System.Linq;
var students = new List { "Алиса", "Борис", "Анна", "Виктор", "Антон" };
// WHERE — фильтрация (как SQL WHERE)
var aNames = students.Where(s => s.StartsWith("А")).ToList();
Console.WriteLine(string.Join(", ", aNames)); // Алиса, Анна, Антон
// SELECT — преобразование (как SQL SELECT)
var lengths = students.Select(s => s.Length).ToList();
Console.WriteLine(string.Join(", ", lengths)); // 5, 5, 4, 6, 5
// ORDER BY — сортировка
var sorted = students.OrderBy(s => s).ToList();
Console.WriteLine(string.Join(", ", sorted)); // Алиса, Анна, Антон, Борис, Виктор
// COUNT, SUM, MIN, MAX — агрегация
var scores = new List { 85, 92, 78, 95, 88, 73, 91 };
Console.WriteLine($"Количество: {scores.Count()}");
Console.WriteLine($"Сумма: {scores.Sum()}");
Console.WriteLine($"Среднее: {scores.Average():F1}");
Console.WriteLine($"Максимум: {scores.Max()}");
Console.WriteLine($"Минимум: {scores.Min()}");
// Цепочка операций
var topScores = scores
.Where(s => s >= 85) // Только отличники (>=85)
.OrderByDescending(s => s) // Сортируем по убыванию
.Take(3) // Берём первые 3
.ToList();
Console.WriteLine(string.Join(", ", topScores)); // 95, 92, 91
Типичные ошибки
Ошибка 1: Бесконечный цикл
// ОПАСНО! Бесконечный цикл — программа зависнет
int i = 0;
while (i < 10)
{
Console.WriteLine(i);
// Забыли i++ !!! Цикл никогда не закончится
}
// ПРАВИЛЬНО:
int j = 0;
while (j < 10)
{
Console.WriteLine(j);
j++; // Не забываем увеличивать счётчик
}
Ошибка 2: Выход за пределы массива
int[] arr = { 1, 2, 3 }; // Индексы: 0, 1, 2
// ОШИБКА!
// Console.WriteLine(arr[3]); // IndexOutOfRangeException!
// ПРАВИЛЬНО:
for (int i = 0; i < arr.Length; i++) // arr.Length = 3, индексы 0,1,2
{
Console.WriteLine(arr[i]);
}
Итого
- ✅ if/else — выбор пути по условию
- ✅ switch — выбор из многих вариантов; switch expression — современный лаконичный синтаксис
- ✅ for — цикл с известным числом итераций
- ✅ while — цикл пока условие истинно
- ✅ do-while — цикл с гарантированным первым выполнением
- ✅ foreach — цикл по каждому элементу коллекции
- ✅ break/continue — прерывание и продолжение цикла
- ✅ LINQ — мощные запросы к коллекциям (Where, Select, OrderBy, Sum, Max...)
Практический проект: угадай число
// Игра "Угадай число" с подсказками и статистикой
var rng = new Random();
int secret = rng.Next(1, 101); // 1 до 100
int attempts = 0;
int maxAttempts = 7;
bool won = false;
Console.WriteLine("=== Угадай число от 1 до 100 ===");
Console.WriteLine($"У тебя {maxAttempts} попыток. Удачи!");
while (attempts < maxAttempts && !won)
{
Console.Write($"\nПопытка {attempts + 1}/{maxAttempts}: ");
if (!int.TryParse(Console.ReadLine(), out int guess) || guess < 1 || guess > 100)
{
Console.WriteLine("Введи число от 1 до 100!");
continue;
}
attempts++;
int diff = Math.Abs(secret - guess);
if (guess == secret)
{
won = true;
}
else
{
string hint = diff switch
{
1 => "🔥 Горячо! Очень близко!",
<= 5 => "♨️ Тепло, совсем рядом",
<= 15 => "😊 Тепловато",
<= 30 => "🌡️ Прохладно",
_ => "❄️ Холодно!"
};
string direction = guess < secret ? "Больше ↑" : "Меньше ↓";
Console.WriteLine($"{hint} ({direction})");
}
}
if (won)
Console.WriteLine($"\n🎉 Поздравляю! Ты угадал {secret} за {attempts} попыток!");
else
Console.WriteLine($"\n😔 Не угадал. Загаданное число: {secret}");
LINQ: query синтаксис vs методный
record Product(string Name, string Category, decimal Price, int Stock);
var products = new List
{
new("Ноутбук", "Электроника", 89999m, 5),
new("Мышь", "Электроника", 1299m, 50),
new("Стол", "Мебель", 15000m, 10),
new("Кресло", "Мебель", 25000m, 7),
new("Наушники", "Электроника", 8999m, 20),
new("Лампа", "Мебель", 3500m, 15),
};
// Методный синтаксис
var electronics = products
.Where(p => p.Category == "Электроника")
.OrderBy(p => p.Price)
.Select(p => $"{p.Name}: {p.Price:C} (осталось: {p.Stock})")
.ToList();
Console.WriteLine("Электроника по возрастанию цены:");
electronics.ForEach(Console.WriteLine);
// Query синтаксис (более похож на SQL)
var expensive =
from p in products
where p.Price > 10000
orderby p.Price descending
select new { p.Name, p.Price, p.Category };
Console.WriteLine("\nДорогие товары (>10000):");
foreach (var p in expensive)
Console.WriteLine($" {p.Name} ({p.Category}): {p.Price:C}");
// Агрегация по категориям
var byCategory = products
.GroupBy(p => p.Category)
.Select(g => new {
Category = g.Key,
Count = g.Count(),
TotalValue = g.Sum(p => p.Price * p.Stock),
AvgPrice = g.Average(p => p.Price)
});
Console.WriteLine("\nСтатистика по категориям:");
foreach (var c in byCategory)
Console.WriteLine($" {c.Category}: {c.Count} товаров, общая стоимость: {c.TotalValue:C}");
Итого
- ✅ if/else — ветвление по условию
- ✅ switch expression — элегантный выбор из вариантов
- ✅ for/while/do-while/foreach — все виды циклов
- ✅ break/continue — управление циклом
- ✅ LINQ — мощная обработка коллекций за одну строку
- ✅ Тернарный оператор
? :— краткая форма if/else
Вложенные структуры управления
// Матрица — вложенные циклы
int[,] matrix = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
Console.WriteLine("Матрица 3×3:");
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
Console.Write($"{matrix[i, j],4}");
Console.WriteLine();
}
// Найти максимум в матрице
int max = matrix[0, 0];
(int row, int col) maxPos = (0, 0);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (matrix[i, j] > max)
{
max = matrix[i, j];
maxPos = (i, j);
}
Console.WriteLine($"Максимум: {max} на позиции ({maxPos.row}, {maxPos.col})");
Работа с массивами и LINQ
// Полезные LINQ-запросы для реальных задач
var grades = new[] { 85, 92, 78, 95, 88, 73, 91, 67, 84, 96 };
// Статистика
Console.WriteLine($"Оценки: {string.Join(", ", grades)}");
Console.WriteLine($"Средняя: {grades.Average():F1}");
Console.WriteLine($"Выше среднего: {grades.Count(g => g > grades.Average())}");
Console.WriteLine($"Топ-3: {string.Join(", ", grades.OrderByDescending(g => g).Take(3))}");
// Гистограмма
var histogram = grades
.GroupBy(g => g / 10 * 10) // Группируем по десяткам
.OrderBy(g => g.Key)
.Select(g => $"{g.Key}-{g.Key+9}: {'*' + new string('*', g.Count() - 1),-15} ({g.Count()})");
Console.WriteLine("\nГистограмма:");
foreach (var bar in histogram)
Console.WriteLine($" {bar}");