Что происходит, когда объявляется переменная в C#?

Ответ

Объявление переменной (Type name;) резервирует область памяти для хранения значения этого типа. Конкретные действия зависят от контекста объявления и категории типа (значимый или ссылочный).

1. Локальные переменные (внутри метода)

  • Для значимых типов (int, double, struct): Компилятор резервирует память непосредственно в кадре стека текущего метода. Переменная должна быть явно инициализирована перед чтением.
    int number; // Память под 4 байта зарезервирована в стеке.
    // Console.WriteLine(number); // Ошибка компиляции: использование неинициализированной переменной.
    number = 42; // Инициализация.
  • Для ссылочных типов (class): В стеке резервируется память под ссылку (указатель). По умолчанию она имеет значение null. Память под сам объект выделяется только при использовании оператора new.
    string text; // В стеке зарезервировано место для ссылки. text == null.
    text = "Hello"; // Ссылка теперь указывает на объект строки в куче.

2. Поля экземпляра класса

  • Память выделяется как часть памяти объекта, когда создается экземпляр класса (через new).
  • Значимые типы инициализируются значением по умолчанию (0, false).
  • Ссылочные типы инициализируются в null.
    public class MyClass
    {
        public int Id;       // Будет 0 при создании MyClass
        public string Name;  // Будет null при создании MyClass
    }

3. Статические переменные (поля класса)

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

Итог: Объявление — это инструкция компилятору о намерении использовать переменную. Фактическое выделение памяти происходит в момент, определенный контекстом (при входе в метод, при создании объекта и т.д.).

Ответ 18+ 🔞

Слушай, вот объясняю как есть, без этих твоих заумных мануалов. Объявил переменную — и что, думаешь, память сразу в космосе резервируется? Не, чувак, всё зависит от того, где и как ты это написал.

1. Переменные внутри метода (локальные)

Тут всё просто, как три копейки.

  • Если тип простой, значимый (вроде int, double или твоя кастомная struct): компилятор сразу на стеке, прямо в кадре твоего метода, откусывает кусок памяти под размер этого типа. Но! Пока не присвоишь значение — нихуя с ней сделать не можешь. Читать нельзя — компилятор наорет.

    int count; // Место под 4 байта в стеке есть. Но там мусор.
    // int x = count; // Ошибка! Использование неинициализированной хуйни.
    count = 10; // Вот теперь окей.
  • Если тип ссылочный (class какой-нибудь): в стеке резервируется место только под ссылку (это как адрес на бумажке). По умолчанию там null — бумажка пустая. А сам объект, его реальное тело, в памяти не появляется, пока ты не скажешь new.

    MyClass obj; // В стеке — бумажка под адрес. На ней написано "пусто".
    obj = new MyClass(); // А вот теперь в куче создался объект, и адрес на него записан в эту бумажку.

2. Поля в классе (не статические)

Это уже история про объекты. Когда ты создаёшь объект через new, под него одним куском выделяется память. В этот кусок автоматом входят все его поля.

  • Значимые поля (int, bool и т.д.) просто кладутся туда со своими дефолтными значениями (0, false).
  • Ссылочные поля (string, другие классы) тоже кладутся, но как пустые ссылки (null).
public class Character
{
    public int Health; // Будет 0 у нового персонажа. Не 100, а 0, запомни!
    public Weapon Gun; // Будет null. Пистолета нет, пока не дашь.
}
// Character hero = new Character();
// Память под hero выделилась, Health = 0, Gun = null.

3. Статические поля (они же переменные класса)

Вот это уже поинтереснее. Они живут не в объектах, а в самом классе. Место под них резервируется, когда класс впервые понадобился в программе (тебе вызвали статик метод, создали первый экземпляр — короче, тронули класс). И живут они до скончания времён (ну или пока домен приложения не выгрузится).

Инициализируются тоже по дефолту, а потом, если есть статический конструктор, он своё дело делает.

Короче, суть: Само объявление Type name; — это просто заявка, "я буду такое использовать". А реальная память под это дело выделяется в конкретный момент: при заходе в метод, при создании объекта или при первом обращении к классу. Не раньше. Всё логично, если не выёбываться.