Ссылочные типы (классы], наоборот, размещаются в управляемой динамически распределяемой памяти (managed heap). Эти объекты остаются в памяти до тех пор, пока сборщик мусора .NET не уничтожит их. По умолчанию в результате присваивания ссылочных типов создается новая ссылка на
// Классы всегда оказываются ссылочными типами,
class MyPoint { // ‹= Теперь это класс!
public int х, у;
}
Если выполнить программу теперь, то можно заметить изменения в ее поведении (рис. 3.13).
Рис. 3.13. Для ссылочных типов присваивание означает копирование ссылки
В данном случае имеется две ссылки на один и тот же объект в управляемой динамической памяти. Поэтому, если изменить значение x с помощью ссылки р2, то мы увидим, что p1.х укажет на измененное значение.
Типы, характеризуемые значениями и содержащие ссылочные типы
Теперь, когда вы чувствуете разницу между типами, характеризуемыми значением, и ссылочными типами, давайте рассмотрим более сложный пример. Предположим, что имеется следующий ссылочный тип (класс), обрабатывающий информационную строку, которую можно установить с помощью пользовательского конструктора.
class ShapeInfo {
public string infoString;
public ShapeInfo(string info) { infoString = info; }
}
Предположим также, что вы хотите поместить переменную этого типа класса в тип с именем MyReсtangle (прямоугольник), характеризуемый значением. Чтобы позволить внешним объектам устанавливать значение внутреннего поля ShapeInfо, вы должны создать новый конструктор (при этом конструктор структуры, заданный по умолчанию, является зарезервированным и не допускает переопределения).
struct MyRectangle {
// Структура MyRectangle содержит член ссылочного типа.
public ShapeInfo reсtInfo;
public int top, left, bottom, right;
public MyRactangle(string info) {
rectInfo = new ShapeInfo(info);
top = left = 10;
bottom = right = 100;
}
}
Теперь вы имеете ссылочный тип. внутри типа, характеризуемого значением. И здесь возникает вопрос на миллион долларов: что случится, если присвоить одну переменную типа MyRectangle другой такой же переменной? С учетом того, что вы уже знаете о типах, характеризуемых значениями, вы можете сделать правильное предположение о том, что целые данные (которые на самом деле и формируют эту структуру) для каждой переменной MyRectangle должны быть независимыми элементами. Но что можно сказать о внутреннем ссылочном типе? Будет скопировано полное состояние этого объекта или будет скопирована
static void Main(string[] args) {
// Создание первого объекта MyRectangle.
Console.WriteLine("-› Создание r1");
MyRectangle r1 = new MyRectangle("Это мой первый прямоугольник");
// Присваивание новому MyRectangle значений r1.
Console.WriteLine("-› Присваивание r1 типу r2");
MyRectangle r2;
r2 = r1;
// Изменение значений r2.
Console.WriteLine("-› Изменение значений r2");
r2.rectInfo.InfoString = "Это новая информация!");
r2.bottom = 4444;
// Print values
Console.WriteLine("-› Значения после изменений:");
Console.WriteLine("-› r1.rectInfo.infoString: {0}", r1.rectInfo.infoString);
Console.WriteLine("-› r2.rectInfo.infoString: {0}", r2.rectInfo.infoString);
Console.WriteLine("-› r1.bottom: {0}", r1.bottom);
Console.WriteLine("-› r2.bottom: {0}", r2.bottom);
}
Рис. 3.14. Внутренние ссылки указывают на один и тот же объект