Всегда ли структура (struct) хранится в стеке в C#?

Ответ

Нет, структура (struct) не всегда хранится в стеке. Будучи типом значения (value type), её расположение в памяти зависит от контекста.

Где может находиться struct:

  1. В стеке: Как локальная переменная внутри метода, если она не захвачена замыканием.
  2. В куче (heap): Когда она является:
    • Поле класса.
    • Элементом массива.
    • Упакована (boxed) в object или интерфейсный тип.
    • Захвачена замыканием (лямбда-выражением).

Пример, демонстрирующий разные случаи:

struct Point { public int X, Y; }

class MyClass
{
    private Point _fieldPoint; // Хранится в куче (в составе объекта MyClass)
}

void Example()
{
    Point localPoint; // Хранится в стеке
    localPoint.X = 5;

    Point[] pointArray = new Point[10]; // Массив структур хранится в куче
    pointArray[0] = localPoint;

    object boxedPoint = localPoint; // Упаковка (boxing) - копия структуры помещается в кучу
}

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

Ответ 18+ 🔞

Давай разберёмся с этими структурами, а то народ путается, как последние идиоты. Слышал сто раз: «структура — она в стеке, класс — в куче». Идиотизм редкий, блядь. Как будто по мантре живут, не думая головой.

Вот смотри, структура — это тип-значение, да. Но это не билет в один конец на стековый поезд. Где она окажется — зависит от того, куда её, блядь, пристроили.

Где эта падла может оказаться:

  1. В стеке. Да, классика. Объявил локальную переменную в методе — и она там, если её, конечно, лямбда какая-нибудь не схавала.
  2. В куче (в аду сборщика мусора). А вот это многих выносит, но это факт жизни. Она в куче, когда:
    • Поле в классе. Класс-то живёт в куче, и всё его нутро — там же. Значит, и структура-поле — там.
    • Элемент массива. new Point[100] — массив-то в куче, сука. И все сто твоих Point — тоже в куче, как ни крути.
    • Упакована (boxed). Это когда ты свою структуру в object или в переменную интерфейсного типа запихнул. Ёбнулся? Поздравляю, она теперь в куче в красивом обёрточном ящике.
    • Захвачена замыканием. Лямбда её прихватизировала — всё, поехала в кучу.

Пример, чтобы до всех дошло, как до жирафа:

struct Point { public int X, Y; } // Вот она, наша героиня

class MyClass // Этот товарищ всегда в куче
{
    private Point _fieldPoint; // И эта точка — тоже в куче, как часть объекта!
}

void Example()
{
    Point localPoint; // А вот эта — да, в стеке (пока что).
    localPoint.X = 5;

    Point[] pointArray = new Point[10]; // Массив создали — он в куче.
    pointArray[0] = localPoint; // И нулевой элемент — тоже в куче, ебать!

    object boxedPoint = localPoint; // УПАКОВКА! Вжух! Теперь копия структуры сидит в куче, в коробке.
}

Так что запомни, а? Не надо по месту жительства структуры судить. Её главная фишка — семантика копирования по значению. Скопировали — получили два независимых куска данных. А уж где эти куски лежат — в стеке, в куче, в жопе у сборщика мусора — это уже детали реализации, на которые лучше не закладываться. Думай о поведении, а не о мифическом «стеке ради скорости». Иначе охуеешь потом, когда оптимизации не будет.