Узнал что массивы в C#-это типы ссылок и они хранятся в куче,которая используется для динамичного выделения памяти.Но вот вопрос:для чего массиву динамичное выдиление памяти?.Вот например мы объявляем массив int[] newArray = new [4]; Мы заранее знаем что массив будет принимать 4 елемнта типа Int32 и мы заранее знаем сколько памяти ему потребуется.Так почему массивы-типы ссылок?
"Сколько памяти потребуется" важно не столько при выделении памяти, сколько при хранении массива в других объектах.
Например, у вас есть класс вида
class A
{
public int fieldA;
public int fieldB;
}
И есть работающий с ним код вида
var a = new A();
a.fieldB = 42;
Перед реальным выполнением этот код надо превратить в код для конкретной платформы. JIT компилятор, который этим занимается, заранее знает, сколько объект типа A занимает в памяти, и по какому смещению в нем лежит поле fieldB:
[0 header][+24 fieldA][+28 fieldB] // 24 - условный размер заголовка
и он генеренирует что-то вроде
mov [a + 28], 42 // положить по адресу a + смещение в нем поля fieldB значение 42
И все это работает быстро. Теперь добавим поле-массив (в котором может лежать массив, а может и не лежать):
class A
{
public int fieldA;
public int[] fieldArray;
public int fieldB;
}
Получаем объект вида
[0 header][+24 fieldA][+28 fieldArray][+32 fieldB] // размер fieldArray предсказуем, т.к. массив - ссылочный тип, и в этом поле лежит адрес массива.
и код при выполнении
mov [a + 32], 42 // положить по адресу a + смещение в нем поля fieldB значение 42
Ок, теперь представим что int[] - это value type.
[0 header][+24 fieldA][+28 fieldArray][+??? fieldB] // размер fieldArray заранее неизвестен
Как теперь в этой ситуации записать значение в fieldB? Реально проверять размер массива перед каждым обращением в соседнее поле? Перекомпилировать метод из IL в C# заново под каждый объект? Дорого, сложно и неэффективно. Разрешить массивы (и, соответственно, строчки) только заранее известной длины? Ну тогда на языке вообще будет тяжело что-то реальное написать :)
А вот если убрать необходимость как-то хранить массивы в других объектах - то все ок, можно делать из них value type. Именно так сделано для структуры Span<T>, которая, по сути, и есть value type array.
Вот, выделяет 100 байт чистейшего стека, без всяких там ссылок:
Span<byte> stackSpan = stackalloc byte[100];
На вопрос "Почему?" краткий ответ таков: потому что на данный момент так сделано.
Можно ли сделать иначе: если массив умещается на стеке - размещать его там, не умещается - размещать в куче? Да, можно. В JVM делается именно так (во всяком случае, в некоторых реализациях HotSpot). Почему не сделано в CLR? Не всё сразу. Разработчики .NET предпочли реализовывать другие фичи (значимые типы, дженерики, указатели на неуправляемую память и пр.)
Однако, работы по определению, где выгоднее разместить объекты, ведутся. Object Stack Allocation. Надеюсь, эти теоретические работы перейдут в практическую плоскость.
Потому что можно сделать так:
int[] i;
i = new int[15];
//тут какое либо использование
i = new int[25];
//ещё что либо
n = int.Parse(Console.ReadLine()/*Любой другой способ получения информации от пользователя*/)
i = new int[n];
//ещё что либо
А если быть более честым, то c# полностью объектно-ориентированный, и всё что в нём есть - объект, а объект - это составная сущность которая занимает (зачастую) неопределённое количество памяти.
Мы заранее знаем что массив будет принимать 4 елемнта типа Int32 и мы заранее знаем сколько памяти ему потребуется.
Да и тут я бы с вами поспорил. А как же вычисление значений не на этапе компиляции, а в рантайме?(во время выполнения)
Простой пример, который я часто использую: мне бывает лень объявлять масивчики и я пользуюсь таким методом(читай: отрывок паттерна Фабрика. хоть вообще не красивый, не правильный и нельзя так делать, но блин удобно)
GetArr<T>(int lenght)=> new T[lenght];
Это универсальный метод для создания Массива любого типа.
А ещё, небольшая разница между тем же самым Int32. Это не класс а структура, а структуры являются TypeValue - значениями, и соответственно хранятся в стеке, а Array является производным от Object, и соответственно располагается в Куче
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости