Лекция 2. Типы значений и ссылочные типы

Ранее мы рассматривали следующие элементарные типы данных: int, byte, double, string, object и др. Также есть сложные типы: структуры, перечисления, классы. Все эти типы данных можно разделить на типы значений, еще называемые значимыми типами, (value types) и ссылочные типы (reference types). Важно понимать между ними различия.

Типы значений:

· Целочисленные типы (byte, sbyte, char, short, ushort, int, uint, long, ulong)

· Типы с плавающей запятой (float, double)

· Тип decimal

· Тип bool

· Перечисления enum

· Структуры (struct)

Ссылочные типы:

· Тип object

· Тип string

· Классы (class)

· Интерфейсы (interface)

· Делегаты (delegate)

В чем же между ними различия? Для этого надо понять организацию памяти в.NET. Здесь память делится на два типа: стек и куча (heap). Параметры и переменные метода, которые представляют типы значений, размещают свое значение в стеке. Стек представляет собой структуру данных, которая растет снизу вверх: каждый новый добавляемый элемент помещаются поверх предыдущего. Время жизни переменных таких типов ограничено их контекстом. Физически стек - это некоторая область памяти в адресном пространстве.

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

Например:

class Program

{

           static void Main(string[] args)

{

                          Calculate(5);

   Console.ReadKey();

}

 

           static void Calculate(int t)

{

                          int x = 6;

   int y = 7;

   int z = y + t;

           }

}

При запуске такой программы в стеке будут определяться два фрейма - для метода Main (так как он вызывается при запуске программы) и для метода Calculate:

При вызове этого метода Calculate в его фрейм в стеке будут помещаться значения t, x, y и z. Они определяются в контексте данного метода. Когда метод отработает, все эти переменные уничтожаются, и память в стеке очищается.

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

Ссылочные типы хранятся в куче или хипе, которую можно представить как неупорядоченный набор разнородных объектов. Физически это остальная часть памяти, которая доступна процессу.

При создании объекта ссылочного типа в стеке помещается ссылка на адрес в куче (хипе). Когда объект ссылочного типа перестает использоваться, то ссылка из стека удаляется, и память очищается. После этого в дело вступает автоматический сборщик мусора: он видит, что на объект в хипе нету больше ссылок, и удаляет этот объект и очищает память.

Так, в частности, если мы изменим метод Calculate следующим образом:

static void Calculate(int t)

{

           object x = 6;

int y = 7;

int z = y + t;

}

То теперь значение переменной x будет храниться в куче, так как она представляет ссылочный тип object, а в стеке будет храниться ссылка на объект в куче.

Составные типы

Теперь рассмотим ситуацию, когда тип значений и ссылочный тип представляют составные типы - структуру и класс:

class Program

{

           private static void Main(string[] args)

           {

   State state1 = new State(); // State - структура, ее данные размещены в стеке

   Country country1 = new Country(); // Country - класс, в стек помещается ссылка на адрес в хипе

                                   // а в хипе располагаются все данные объекта country1

}

}

struct State

{

public int x;

public int y;

           public Country country;

}

class Country

{

public int x;

public int y;

}

Здесь в методе Main в стеке выделяется память для объекта state1. Далее в стеке создается ссылка для объекта country1 (Country country1), а с помощью конструктора выделяется место в хипе (new Country()). Ссылка в стеке для объекта country1 будет представлять адрес на место в хипе, по которому размещен данный объект..

Таким образом, в стеке окажутся все поля структуры state1 и ссылка на объект country1 в хипе.

Однако в структуре State также определена переменная ссылочного типа Country. Где она будет хранить свое значение, если она определена в типе значений?

private static void Main(string[] args)

{

           State state1 = new State();

           state1.country = new Country();

           Country country1 = new Country();

}

Значение переменной state1.country также будет храниться в куче, так как эта переменная представляет ссылочный тип:

Копирование значений

Тип данных надо учитывать при копировании значений. При присвоении данных объекту значимого типа он получает копию данных. При присвоении данных объекту ссылочного типа он получает не копию объекта, а ссылку на этот объект в хипе. Например:

private static void Main(string[] args)

{

State state1 = new State(); // Структура State

State state2 = new State();

state2.x = 1;

state2.y = 2;

state1 = state2;

state2.x = 5; // state1.x=1 по-прежнему

           Console.WriteLine(state1.x); // 1

Console.WriteLine(state2.x); // 5

 

Country country1 = new Country(); // Класс Country

Country country2 = new Country();

country2.x = 1;

country2.y = 4;

country1 = country2;

country2.x = 7; // теперь и country1.x = 7, так как обе ссылки и country1 и country2

               // указывают на один объект в хипе

           Console.WriteLine(country1.x); // 7

Console.WriteLine(country2.x); // 7

               

           Console.Read();

}

Так как state1 - структура, то при присвоении state1 = state2 она получает копию структуры state2. А объект класса country1 при присвоении country1 = country2; получает ссылку на тот же объект, на который указывает country2. Поэтому с изменением country2, так же будет меняться и country1.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: