🔷 C#

Condiciones (if/else/switch) en C# (.NET 6): guía detallada

Переменные и типы данных в C#: полное руководство с примерами

Представь, что ты пишешь кулинарный рецепт. Тебе нужно где-то записать: «100 граммов муки», «2 яйца», «название блюда — Пирог». Переменные в программировании — это точно такие же «ячейки памяти» для хранения данных. Давай разберёмся, как они работают в C#.

Что такое переменная и зачем она нужна

Переменная — это именованная область памяти компьютера, в которой хранится какое-то значение. Представь компьютерную память как огромный склад с ящиками. Каждый ящик имеет:

  • Номер (адрес памяти) — компьютер работает с этим
  • Название (имя переменной) — программист работает с этим
  • Содержимое (значение) — данные, которые хранятся
  • Тип ящика (тип данных) — какие данные можно хранить

Без переменных программы были бы практически бесполезны — они не смогли бы запоминать и обрабатывать данные.

Основные типы данных в C#

C# — строго типизированный язык. Это значит, что каждая переменная должна иметь чётко определённый тип данных. Давай познакомимся с основными:

Целые числа: int и другие

Для хранения целых чисел (без дробной части) используется тип int. Это как ящик, в котором можно хранить только целые числа от -2 147 483 648 до 2 147 483 647.

int age = 15;           // Возраст
int temperature = -5;   // Температура (может быть отрицательной)
int score = 1500;       // Очки в игре
int population = 144000000; // Население страны

Console.WriteLine($"Возраст: {age}");
Console.WriteLine($"Температура: {temperature}°C");

// Математические операции с int
int a = 10;
int b = 3;
Console.WriteLine(a + b);  // 13
Console.WriteLine(a - b);  // 7
Console.WriteLine(a * b);  // 30
Console.WriteLine(a / b);  // 3 (ЦЕЛОЧИСЛЕННОЕ деление!)
Console.WriteLine(a % b);  // 1 (остаток от деления)

Важно! При делении двух целых чисел результат тоже будет целым. 10 / 3 = 3 (не 3.33). Если нужна дробная часть — читай про double ниже.

Есть и другие типы для целых чисел:

byte smallNumber = 255;        // 0 до 255 (1 байт)
short mediumNumber = 32000;    // -32768 до 32767 (2 байта)
int regularNumber = 1000000;   // ~±2 млрд (4 байта)
long bigNumber = 9000000000L;  // ~±9 квинтиллионов (8 байт), суффикс L

// Беззнаковые (только положительные)
uint positiveOnly = 4000000000U; // суффикс U
ulong veryBig = 18000000000000000000UL;

Числа с дробной частью: double и float

double height = 1.75;        // Рост в метрах
double pi = 3.14159265358979; // Число Пи
double temperature = 36.6;   // Температура тела

float lessAccurate = 3.14f;  // float требует суффикс f, менее точный

// Пример вычислений
double radius = 5.0;
double area = pi * radius * radius;
Console.WriteLine($"Площадь круга: {area:F2}"); // :F2 — два знака после запятой
// Результат: Площадь круга: 78.54

double vs float: double хранит 15-17 значимых цифр, float — только 7. Используй double по умолчанию, float только когда критична скорость или память.

Тип decimal: точные деньги

Если ты работаешь с деньгами или финансами — всегда используй decimal. Вот почему:

// ПРОБЛЕМА с double при работе с деньгами:
double moneyDouble = 0.1 + 0.2;
Console.WriteLine(moneyDouble); // 0.30000000000000004 — ОШИБКА!

// РЕШЕНИЕ — decimal точен:
decimal moneyDecimal = 0.1m + 0.2m; // суффикс m обязателен
Console.WriteLine(moneyDecimal); // 0.3 — точно!

// Финансовые расчёты
decimal price = 1299.99m;
decimal discount = 0.15m; // 15% скидка
decimal finalPrice = price * (1 - discount);
Console.WriteLine($"Цена со скидкой: {finalPrice:C}"); // :C — формат валюты

Правило: Деньги → decimal. Физика/математика → double. Остальное → int.

Булев тип: bool

Тип bool хранит только два значения: true (истина) или false (ложь). Это как выключатель — или включён, или выключен.

bool isRaining = false;
bool hasHomework = true;
bool isAdult = false;

// Логические операции
bool bothTrue = true && true;   // true (И: оба должны быть true)
bool eitherTrue = false || true; // true (ИЛИ: хотя бы один true)
bool notTrue = !true;            // false (НЕ: инверсия)

// Часто используется для условий
int playerHealth = 50;
bool isAlive = playerHealth > 0; // true
bool isDead = playerHealth <= 0; // false

Console.WriteLine($"Игрок жив: {isAlive}");

Символьный тип: char

Тип char хранит один символ. Обрати внимание: одинарные кавычки!

char grade = 'A';       // Оценка
char initial = 'Д';     // Инициал (поддерживает Unicode)
char digit = '5';       // Цифра как символ (не число!)
char space = ' ';       // Пробел
char newLine = '\n';    // Перевод строки (специальный символ)

Console.WriteLine(grade);  // A

// char можно сравнивать
char letter = 'c';
bool isUpperCase = char.IsUpper(letter); // false
bool isLetter = char.IsLetter(letter);   // true
char upper = char.ToUpper(letter);       // 'C'

Строки: string

Тип string хранит текст — последовательность символов. Двойные кавычки!

string name = "Александр";
string greeting = "Привет, мир!";
string empty = "";              // Пустая строка
string nullString = null;       // Нет значения вообще

// Операции со строками
string firstName = "Иван";
string lastName = "Петров";
string fullName = firstName + " " + lastName; // Конкатенация
Console.WriteLine(fullName); // Иван Петров

// Методы строк
Console.WriteLine(name.Length);        // 9 — длина строки
Console.WriteLine(name.ToUpper());     // АЛЕКСАНДР
Console.WriteLine(name.ToLower());     // александр
Console.WriteLine(name.Contains("кс")); // True
Console.WriteLine(name.Replace("Але", "Все")); // Всександр

// Проверка пустоты
bool isEmpty = string.IsNullOrEmpty(nullString); // true
bool isWhitespace = string.IsNullOrWhiteSpace("   "); // true

Ключевое слово var: когда тип угадывает компилятор

В C# есть умная функция: если ты инициализируешь переменную сразу при объявлении, компилятор может сам угадать тип. Для этого используется ключевое слово var.

// Явное указание типа (традиционно)
int count = 42;
string message = "Hello";
double price = 9.99;

// Неявная типизация с var (современный стиль)
var count2 = 42;       // компилятор видит 42 → int
var message2 = "Hello"; // компилятор видит строку → string
var price2 = 9.99;     // компилятор видит 9.99 → double

// var НЕ делает переменную динамической!
var number = 10;
// number = "текст"; // ОШИБКА! number - это int, уже нельзя менять тип

// Полезно для длинных типов
var list = new List(); // вместо List list = new List();
var dict = new Dictionary(); // удобно!

Когда использовать var? Когда тип очевиден из правой части выражения. Когда тип длинный и неудобный. Когда тип — результат LINQ-запроса.

Константы: const и readonly

Иногда нужна переменная, значение которой нельзя изменить — константа.

// const — значение известно при компиляции, нельзя изменить
const double Pi = 3.14159265358979;
const int MaxPlayers = 100;
const string AppName = "МояИгра";

// Попытка изменить константу вызовет ошибку компиляции:
// Pi = 3.14; // Ошибка! Cannot assign to 'Pi' because it is a constant

// readonly — значение задаётся при инициализации или в конструкторе
readonly DateTime startTime = DateTime.Now;
// startTime = DateTime.Now; // Ошибка после инициализации!

Разница: const вычисляется при компиляции, readonly — при запуске программы. Используй const для математических констант и настроек. readonly — для значений, которые могут зависеть от условий запуска.

Nullable типы: когда значения может не быть

Обычный int всегда хранит какое-то число. Но что если число не задано? Например, возраст пользователя в форме — он мог не указать его. Для таких случаев есть nullable типы.

// Обычный int — не может быть null
int regularAge = 25;
// regularAge = null; // ОШИБКА! int не может быть null

// Nullable int — может быть null (не задан)
int? nullableAge = null;     // Возраст не указан
int? confirmedAge = 25;      // Возраст указан

// Проверка на null
if (nullableAge == null)
{
    Console.WriteLine("Возраст не указан");
}

if (confirmedAge.HasValue)
{
    Console.WriteLine($"Возраст: {confirmedAge.Value}");
}

// Оператор ?? (null-coalescing) — значение по умолчанию
int displayAge = nullableAge ?? 0; // Если null — используем 0
Console.WriteLine($"Показываем: {displayAge}"); // 0

// Nullable для других типов
double? weight = null;
bool? isVerified = null;
string? nullableString = null; // В C# 8+ строки тоже можно пометить ?

Зачем нужны nullable? В базах данных поля могут быть NULL. В формах пользователь может не заполнить поле. Nullable типы позволяют корректно работать с «отсутствием значения».

Преобразование типов

Иногда нужно преобразовать одно значение в другой тип. В C# это делается несколькими способами:

Неявное преобразование (автоматическое)

// Из меньшего типа в больший — автоматически
int smallNumber = 42;
long bigNumber = smallNumber; // int → long (безопасно, места больше)
float f = smallNumber;        // int → float (автоматически)
double d = smallNumber;       // int → double (автоматически)

Console.WriteLine(bigNumber); // 42

Явное преобразование (casting)

// Из большего типа в меньший — нужно явное преобразование
double pi = 3.14159;
int intPi = (int)pi; // Явное преобразование — дробная часть ОТБРАСЫВАЕТСЯ
Console.WriteLine(intPi); // 3 (не 3.14!)

long bigNum = 100000L;
int smallNum = (int)bigNum; // Может потерять данные если bigNum > int.MaxValue

// ОПАСНО: переполнение
int maxInt = int.MaxValue; // 2 147 483 647
int overflow = maxInt + 1;  // -2 147 483 648 — переполнение!

Преобразование строк в числа

// Строка → число
string ageText = "25";
int age = int.Parse(ageText);        // Кидает исключение если строка не число
int age2 = Convert.ToInt32(ageText); // Аналогично

// Безопасный способ с TryParse
string userInput = "abc";
bool success = int.TryParse(userInput, out int result);
if (success)
{
    Console.WriteLine($"Число: {result}");
}
else
{
    Console.WriteLine("Это не число!");
}

// Число → строка
int number = 42;
string text = number.ToString();         // "42"
string formatted = number.ToString("D5"); // "00042" — 5 цифр с нулями
string hex = number.ToString("X");       // "2A" — шестнадцатеричное

Имена переменных: как называть правильно

// ПРАВИЛЬНЫЕ имена (camelCase для локальных переменных)
int playerHealth = 100;
string userName = "Alex";
double distanceInKilometers = 42.5;
bool isGameOver = false;

// НЕПРАВИЛЬНЫЕ имена (компилятор не примет)
// int 1number = 5;    // Нельзя начинать с цифры
// int my-var = 5;     // Дефис запрещён
// int class = 5;      // class — зарезервированное слово

// Зарезервированные слова нельзя использовать как имена:
// int, string, bool, if, else, for, while, class, return, void...

// Соглашения именования в C#:
int localVariable = 5;         // camelCase для локальных
const int MAX_SIZE = 100;      // UPPER_CASE для констант (или PascalCase)
string _privateField = "val";  // _camelCase для приватных полей класса

Типичные ошибки с переменными

Ошибка 1: Использование переменной до инициализации

int x;
// Console.WriteLine(x); // ОШИБКА! Use of unassigned local variable 'x'

int y = 0; // Инициализируем нулём
Console.WriteLine(y); // 0 — OK

Ошибка 2: Деление на ноль

int a = 10;
int b = 0;
// int result = a / b; // DivideByZeroException — исключение при выполнении!

// Проверяй перед делением:
if (b != 0)
{
    int result = a / b;
    Console.WriteLine(result);
}

Ошибка 3: Переполнение int

int big = 2_000_000_000; // Нижние черты можно использовать для читаемости
int bigger = big + big;  // Переполнение! Результат отрицательный

// Решение: использовать long
long safeBig = (long)big + big; // Явно преобразуем в long перед сложением

Итого

Что ты узнал в этом уроке:

  • ✅ int — целые числа (возраст, счёт, количество)
  • ✅ double — числа с дробной частью (рост, вес, координаты)
  • ✅ decimal — точные дробные числа (деньги, финансы)
  • ✅ bool — истина или ложь (true/false)
  • ✅ char — один символ в одинарных кавычках
  • ✅ string — текст в двойных кавычках
  • ✅ var — компилятор сам определяет тип
  • ✅ const — константа, нельзя изменить
  • ✅ int? — nullable тип, может быть null (значение отсутствует)
  • ✅ Преобразование типов: неявное (автомат), явное (casting), Parse/TryParse

Практический мини-проект: форма регистрации

// Симуляция формы регистрации пользователя
Console.WriteLine("=== Регистрация пользователя ===\n");

// Имя пользователя
string? userName = null;
while (string.IsNullOrWhiteSpace(userName))
{
    Console.Write("Имя пользователя (3-20 символов): ");
    userName = Console.ReadLine()?.Trim();
    if (userName?.Length < 3 || userName?.Length > 20)
    {
        Console.WriteLine("Имя должно быть от 3 до 20 символов!");
        userName = null;
    }
}

// Возраст
int? age = null;
while (age is null)
{
    Console.Write("Ваш возраст: ");
    if (int.TryParse(Console.ReadLine(), out int parsedAge) && parsedAge >= 13 && parsedAge <= 120)
        age = parsedAge;
    else
        Console.WriteLine("Введите корректный возраст (13-120)!");
}

// Email (простая проверка)
string? email = null;
while (email is null)
{
    Console.Write("Email адрес: ");
    string? input = Console.ReadLine()?.Trim().ToLower();
    if (input?.Contains('@') == true && input.Contains('.'))
        email = input;
    else
        Console.WriteLine("Введите корректный email!");
}

// Вывод результата
Console.WriteLine("\n=== Данные зарегистрированы ===");
Console.WriteLine($"Логин: {userName}");
Console.WriteLine($"Возраст: {age} лет");
Console.WriteLine($"Email: {email}");
Console.WriteLine($"Совершеннолетний: {(age >= 18 ? "Да" : "Нет")}");
Console.WriteLine($"Дата регистрации: {DateTime.Now:dd.MM.yyyy HH:mm}");

Таблица всех числовых типов C#

Для удобства — полная таблица числовых типов:

// Тип     | Размер | Диапазон                    | Использование
// --------|--------|-----------------------------|-----------------------
// sbyte   | 1 байт | -128 до 127                 | Маленькие числа со знаком
// byte    | 1 байт | 0 до 255                    | Байты, цвета (R,G,B)
// short   | 2 байт | -32,768 до 32,767           | Координаты, высоты
// ushort  | 2 байт | 0 до 65,535                 | Порты (0-65535)
// int     | 4 байт | -2,147,483,648 до +2млрд   | ОСНОВНОЙ — всё остальное
// uint    | 4 байт | 0 до 4,294,967,295          | Счётчики без отрицат.
// long    | 8 байт | ~-9.2×10^18 до +9.2×10^18  | Большие числа
// ulong   | 8 байт | 0 до ~1.8×10^19             | Очень большие положит.
// float   | 4 байт | ~±1.5×10^-45 до ±3.4×10^38 | Игровая графика
// double  | 8 байт | ~±5.0×10^-324 до ±1.8×10^308| Научные расчёты
// decimal | 16 байт| ±7.9×10^-28 до ±7.9×10^28 | ДЕНЬГИ и финансы
// bool    | 1 байт | true / false               | Логика, флаги
// char    | 2 байт | U+0000 до U+FFFF           | Один Unicode символ
// string  | Разный | Текст произвольной длины   | Строки

Арифметика с разными типами

// Правила арифметики в C#

// int op int = int (даже результат дроби = целое!)
int a = 7, b = 2;
Console.WriteLine(a / b);      // 3, не 3.5!
Console.WriteLine(a % b);      // 1 (остаток)

// int op double = double (повышение типа)
int c = 5;
double d = 2.0;
Console.WriteLine(c / d);     // 2.5 (c автоматически конвертируется в double)

// Явное преобразование для дробного деления int/int
Console.WriteLine((double)a / b); // 3.5
Console.WriteLine(a / (double)b); // 3.5

// Математические функции (System.Math)
Console.WriteLine(Math.Abs(-42));         // 42 — абсолютное значение
Console.WriteLine(Math.Sqrt(16));         // 4 — квадратный корень
Console.WriteLine(Math.Pow(2, 10));       // 1024 — степень
Console.WriteLine(Math.Round(3.7));       // 4 — округление
Console.WriteLine(Math.Floor(3.9));       // 3 — округление вниз
Console.WriteLine(Math.Ceiling(3.1));     // 4 — округление вверх
Console.WriteLine(Math.Max(5, 10));       // 10 — максимум
Console.WriteLine(Math.Min(5, 10));       // 5 — минимум
Console.WriteLine(Math.Log(Math.E));      // 1 — натуральный логарифм