1_Типы данных и переменные

Урок 1 : Типы данных и переменные

О чём этот урок

Переменные - это именованные ячейки памяти для хранения данных. В этом уроке вы узнаете, какие типы данных существуют в C# и как с ними работать.


1. Что такое переменная

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

тип    имя     значение
 ↓      ↓         ↓
int  counter  =   0  ;
Часть Описание Пример
Тип Определяет, какие данные хранятся и сколько памяти занимают int, string, bool
Имя Идентификатор для обращения к переменной counter, playerName
Значение Данные, хранящиеся в переменной 0, "Hero", true
// Объявление и присвоение значения
int health = 100;

// Объявление без значения (значение по умолчанию)
int score;     // score = 0 по умолчанию
string name;   // name = null по умолчанию

// Изменение значения
health = 80;
Соглашения об именовании

  • Переменные пишутся в camelCase: playerHealth, maxSpeed
  • Имена должны быть говорящими: hp хуже, чем currentHealth
  • Нельзя начинать имя с цифры: 2player - ошибка, player2 - норма


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

Целочисленные типы

Тип Размер Диапазон Пример
byte 1 байт 0 … 255 Цвет канала RGB
short 2 байта −32 768 … 32 767 Небольшие счётчики
int 4 байта ≈ −2 млрд … 2 млрд Стандартный целый тип
long 8 байт Очень большой диапазон Метки времени (timestamp)
int lives = 3;
long population = 8_000_000_000L; // L - суффикс для long, _ - разделитель для читаемости

Числа с плавающей точкой

Тип Размер Точность Пример использования
float 4 байта ~7 цифр Позиции, физика в Unity
double 8 байт ~15 цифр Научные расчёты
decimal 16 байт ~28 цифр Финансовые расчёты
float speed = 5.5f;       // f - суффикс обязателен для float!
double pi = 3.14159265;   // double по умолчанию
decimal price = 9.99m;    // m - суффикс для decimal
Суффикс f для float

Без суффикса f значение 5.5 считается double. Написать float x = 5.5; - ошибка компиляции. Всегда пишите 5.5f.

Символы и строки

char letter = 'A';            // Один символ, в одинарных кавычках
string greeting = "Hello!";   // Строка символов, в двойных кавычках
string empty = "";            // Пустая строка
string nullStr = null;        // Отсутствие строки (ссылка на ничто)

Основные методы строк

string - не просто набор символов: у строки есть встроенные методы для работы с текстом.

Метод Что делает Пример Результат
Contains(s) Содержит ли строка подстроку s "Привет мир".Contains("мир") true
Trim() Убирает пробелы с обоих концов " текст ".Trim() "текст"
Replace(a, b) Заменяет все вхождения a на b "а б в".Replace(" ", "") "абв"
Split(c) Разбивает по разделителю c, возвращает string[] "a,b,c".Split(',') {"a","b","c"}
Методы не меняют оригинал

Строка в C# неизменяема: методы возвращают новую строку, а не изменяют существующую. text.Trim() не меняет text - нужно сохранить результат в переменную:

text = text.Trim(); // теперь text обновлён

Логический тип

bool isAlive = true; // isAlive имеет занчение истина
bool hasKey = false; // hasKey имеет значение ложь
bool isGameOver = lives <= 0; // Результат сравнения - тоже bool. Если lives <= 0, isGameOver истина.

Итоговая таблица

Тип Категория Значение по умолчанию
int Целое 0
float Вещественное 0f
double Вещественное 0.0
bool Логический false
char Символ '\0'
string Строка null

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

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

int a = 10;
int b = 3;

int sum  = a + b;  // 13  - сложение
int diff = a - b;  // 7   - вычитание
int prod = a * b;  // 30  - умножение
int quot = a / b;  // 3   - целочисленное деление (дробная часть отбрасывается)
int rem  = a % b;  // 1   - остаток от деления

float x = 10f;
float y = 3f;
float div = x / y; // 3.333...  - деление float даёт дробный результат
Целочисленное деление

10 / 3 равно 3, а не 3.33. Чтобы получить дробный результат, хотя бы один операнд должен быть float/double: 10f / 3 или (float)10 / 3.

Присваивание

int x = 10;   // = присваивает значение
x = 20;       // x теперь равен 20

// Составные операторы присваивания
x += 5;   // x = x + 5  →  25
x -= 3;   // x = x - 3  →  22
x *= 2;   // x = x * 2  →  44
x /= 4;   // x = x / 4  →  11
x %= 3;   // x = x % 3  (остаток от деления) →  2

// Инкремент и декремент
x++;      // x = x + 1
x--;      // x = x - 1

Сравнение

= и == - это разные операторы!

= - присваивает значение переменной.
== - сравнивает два значения и возвращает bool.

int a = 5;
int b = 10;

bool isEqual   = (a == b);  // false - равны ли?
bool notEqual  = (a != b);  // true  - не равны?
bool less      = (a < b);   // true  - меньше?
bool greater   = (a > b);   // false - больше?
bool lessOrEq  = (a <= b);  // true  - меньше или равно?
bool greatOrEq = (a >= b);  // false - больше или равно?

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

bool hasHealth = true;
bool hasAmmo   = false;

bool canFight = hasHealth && hasAmmo;  // && (И): только оба true → true
bool canAct   = hasHealth || hasAmmo;  // || (ИЛИ): хотя бы одно true → true
bool isDead   = !hasHealth;            // ! (НЕ): инвертирует → false

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

Часто нужно перевести данные из одного типа в другой - например, текст от пользователя превратить в число для вычислений или число отобразить как строку.

Строка → число

int.Parse() - преобразует строку в int. Если строка не является числом - программа выдаст ошибку.

string input = "42";
int number = int.Parse(input); // 42

// Аналогично для других типов
float speed  = float.Parse("3.14");
bool isReady = bool.Parse("true"); // "True" или "False" без учёта регистра

Безопасное преобразование: TryParse

int.TryParse() - пробует преобразовать строку. Если не получилось - возвращает false и не выдаёт ошибку.

Console.Write("Введите число: ");
string userInput = Console.ReadLine();

if (int.TryParse(userInput, out int result))
{
    Console.WriteLine($"Вы ввели: {result}");
}
else
{
    Console.WriteLine("Это не число!");
}
Parse vs TryParse

  • Parse - используйте, когда уверены в корректности данных (например, значение задали сами в коде).
  • TryParse - используйте, когда данные приходят от пользователя: не падает при неверном вводе.

Число → строка

Метод ToString() есть у любого типа - он возвращает строковое представление значения:

int score    = 100;
float speed  = 3.14f;
bool isAlive = true;

string s1 = score.ToString();    // "100"
string s2 = speed.ToString();    // "3,14" (зависит от региональных настроек)
string s3 = isAlive.ToString();  // "True"

// На практике чаще используют интерполяцию - она вызывает ToString() автоматически:
Console.WriteLine($"Счёт: {score}, Жив: {isAlive}");

Явное приведение числовых типов

Для преобразования между числовыми типами используется (тип) перед значением:

double d = 9.99;
int i    = (int)d;    // 9 - дробная часть отбрасывается, не округляется!

int a    = 42;
float f  = (float)a;  // 42.0f - расширение без потерь

float x  = 3.7f;
int   n  = (int)x;    // 3 - не 4!
Приведение ≠ округление

(int)3.9 даёт 3, а не 4. Для округления используйте Math.Round().


5. Ключевое слово var

var позволяет не писать тип явно - компилятор выводит его из правой части выражения автоматически. Тип всё равно фиксируется при компиляции (это не динамическая типизация).

var age    = 25;    // компилятор видит 25 → int
var name   = "Алексей"; // видит строку → string
var speed  = 3.5f;// видит float-литерал → float
var player = new Player();// видит класс → Player

// Переменная с var по-прежнему строго типизирована:
age = "текст"; // ОШИБКА: нельзя присвоить строку переменной типа int
Когда использовать var

  • Когда тип очевиден из правой части: var list = new List<int>()
  • Когда имя типа очень длинное: var dict = new Dictionary<string, List<int>>()
  • Избегайте var там, где тип неочевиден: var result = Calculate(); - непонятно, что возвращает Calculate


Для углублённого изучения

Значимые и ссылочные типы

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

Значимые типы (Value Types)

Хранят данные непосредственно в переменной. При присваивании создаётся копия.

int a = 10;
int b = a;   // b - независимая копия
b = 99;

Console.WriteLine(a); // 10 - a не изменился!
Console.WriteLine(b); // 99

К значимым типам относятся: int, float, double, bool, char, struct, enum.

Ссылочные типы (Reference Types)

Хранят адрес (ссылку) на объект в куче памяти (heap). При присваивании копируется ссылка, а не сами данные.

int[] arr1 = { 1, 2, 3 };
int[] arr2 = arr1;   // arr2 указывает на тот же массив!
arr2[0] = 99;

Console.WriteLine(arr1[0]); // 99 - arr1 тоже изменился!

К ссылочным типам относятся: string, class, array, interface.

Стек и куча

Значимые типы хранятся в стеке, ссылочные - в куче. Это разные способы организации памяти: стек быстрый и автоматически очищается, куча позволяет хранить данные произвольного размера.

Особый случай: string

string - ссылочный тип, но ведёт себя похоже на значимый, потому что является неизменяемым (immutable). Каждое «изменение» строки создаёт новый объект в памяти.


Nullable-типы

По умолчанию значимые типы (int, float, bool и др.) не могут содержать null - у них всегда есть конкретное значение. Чтобы разрешить «отсутствие значения», используется знак вопроса после типа: int?.

int  a = null;  // ОШИБКА: int не может быть null
int? b = null;  // OK: nullable int

int? score = null;     // значение не задано
int? level = 5;        // значение есть

// Проверка на null
if (score == null)
    Console.WriteLine("Счёт не известен");

// Свойство HasValue и Value
if (level.HasValue)
    Console.WriteLine($"Уровень: {level.Value}"); // "Уровень: 5"
Тип Может быть null Значение по умолчанию
int Нет 0
int? Да null
bool Нет false
bool? Да null

Оператор ?? - null-coalescing (подстановка при null)

Возвращает левый операнд, если он не null, иначе - правый. Удобно задавать «значение по умолчанию» для nullable-переменных.

int? savedScore = null;
int displayScore = savedScore ?? 0; // savedScore == null → берём 0
Console.WriteLine(displayScore); // 0

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

// Цепочка ??
string result = a ?? b ?? c ?? "по умолчанию";

Оператор ?. - null-conditional (безопасный вызов)

Вызывает метод или обращается к свойству только если объект не null. Если объект null - возвращает null вместо выброса исключения.

string text = null;

// Без ?. - NullReferenceException!
// int len = text.Length;

// С ?. - безопасно
int? len = text?.Length; // null, а не исключение

// Комбинируем ?. и ??
int safeLen = text?.Length ?? 0; // 0, если text == null

// Пример с объектом
Player player = null;
player?.Attack(); // ничего не произойдёт, исключения не будет
?. и ?? вместе

Связка obj?.Property ?? defaultValue - один из самых частых паттернов в C#. Сначала безопасно читаем значение, потом подставляем запасное, если получили null.


Перечисления (enum)

Когда переменная должна принимать одно из нескольких заранее известных именованных значений, вместо «магических» чисел или строк используют enum. Это делает код читаемым и защищает от опечаток.

// Объявление enum (обычно - на уровне пространства имён или класса)
enum Direction
{
    North,   // = 0 по умолчанию
    East,    // = 1
    South,   // = 2
    West     // = 3
}

// Использование
Direction move = Direction.North;
Console.WriteLine(move);        // "North"
Console.WriteLine((int)move);   // 0

Явные числовые значения

Значения элементов можно задать вручную. Незаданные элементы продолжают нумерацию от предыдущего.

enum ItemRarity
{
    Common    = 0,
    Uncommon  = 1,
    Rare      = 10,
    Epic      = 20,
    Legendary = 100
}

ItemRarity drop = ItemRarity.Rare;
Console.WriteLine((int)drop); // 10

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

const

Значение задаётся при компиляции и никогда не меняется. Должно быть известно на этапе написания кода.

const int MaxHealth = 100;
const float Gravity = 9.81f;
const string GameName = "MyGame";

MaxHealth = 200; // ОШИБКА: нельзя изменить константу

readonly

Значение задаётся при инициализации или в конструкторе, после чего не меняется. Подходит для значений, которые неизвестны до запуска программы.

class Config
{
    readonly int startTime;

    Config()
    {
        startTime = (int)DateTime.Now.Ticks; // можно задать в конструкторе
    }
}
Характеристика const readonly
Когда задаётся При компиляции При инициализации или в конструкторе
Может быть полем класса Да Да
Может быть локальной переменной Да Нет
Допустимые типы Только примитивы и string Любые типы

Итог урока


📋 Перейти к практическим заданиям урока 1

Материалы для дополнительного ознакомления :

Переменные и константы
Литералы
Типы данных
Арифметические операции
Условные выражения
Значимые и ссылочные типы
Строки