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

В CTS (и, следовательно, в С#) есть две группы типов — значащие и ссылочные. К значащим относятся большинство примитивных типов (int, float и т. д.), а также перечисления и структуры.

Главным отличием значащих типов от ссылочных является способ их представления в памяти компьютера. Для первых память выделяется в программном стеке, а имя соответствующей переменной прямо связывается с этой памятью. Иными словами, если инициализирована переменная значащего типа, имя этой переменной адресует участок стека, в котором она расположена. Если создается другая переменная того же значащего типа, ей выделяется другая область стека того же размера. Для ссылочных типов память выделяется в управляемой системной куче, а значением переменной этого типа является адрес участка кучи, в которой расположена переменная. Если создается вторая переменная того же ссылочного типа, она получает ссылку на тот же участок кучи, что и первая. Таким образом, переменные одного и того же значащего типа независимы друг от друга, а переменные одинакового ссылочного типа — зависимы.

Это продемонстрирует программа, представленная в листинге 5.1 (файл Ch05\ValRefTypes\Program.cs).

Листинг 5.1. Значащие и ссылочные типы

using System;

// Определяем структуру с двумя целочисленными полями:

struct Foo

{

public int x, y;

}

class ValRefClass

{

static void Main()

{

// Создаем две переменные класса Foo

Foo f1 = new Foo();

Foo f2 = new Foo();

f1.x = 100;

f1.y = 200;

// Присваиваем переменной f1 значение переменной f2:

f2 = f1;

// Выводим значения переменных:

Console.WriteLine("f1.x = {0}", f1.x);

Console.WriteLine("f1.y = {0}", f1.y);

Console.WriteLine("f2.x = {0}", f2.x);

Console.WriteLine("f2.y = {0}", f2.y);

// Изменяем f1:

f1.x = 300;

// Выводим поле х обеих переменных:

Console.WriteLine("После изменения f1.x:");

Console.WriteLine("f1.x = {0}", f1.x);

Console.WriteLine("f2.x = {0}", f2.x);

Console.ReadLine();

}

}

Изменим программу: вместо значащего типа struct используем ссылочный тип class:

class Foo

{

public int x, y;

}

Все значащие типы унаследованы от класса System.ValueType, в то время как ссылочные типы могут быть наследниками любого класса, кроме System.ValueType. Поскольку экземпляры значащих типов располагаются в стеке, а ссылочных — в куче, время жизни первых заканчивается при выходе из области видимости программы (из метода, в котором объявлены соответствующие переменные). Время жизни ссылочных типов определяется алгоритмом сборки мусора.

Класс System.ValueType занимает особое место в иерархии классов CTS. С одной стороны, он является прямым наследником базового класса System.Object, с другой объявляется с модификатором abstract, что исключает возможность использования объектов этого класса. Его назначение — передать своим наследникам некоторую функциональность всех значащих типов, в том числе возможность их преобразования в ссылочный тип и обратно (см. следующий раздел). Другой важной особенностью класса является то обстоятельство, что все его многочисленные потомки (их более 100) являются не классами, а структурами. Структуры в CTS (и в С#) считаются особой разновидностью классов: подобно классам, они инкапсулируют поля и методы, но не обладают свойствами наследования и полиморфизма.

Предлагаю ознакомиться с аналогичными статьями: