Книга: ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание

Типы, характеризуемые значениями и содержащие ссылочные типы

Типы, характеризуемые значениями и содержащие ссылочные типы

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

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 должны быть независимыми элементами. Но что можно сказать о внутреннем ссылочном типе? Будет скопировано полное состояние этого объекта или будет скопирована ссылка на этот объект? Проанализируйте следующий программный код и рассмотрите рис. 3.14, который может подсказать правильный ответ.

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. Внутренние ссылки указывают на один и тот же объект

Как видите, при изменении значения информирующей строки с помощью ссылки r2 ссылка r1 отображает точно такое же значение. По умолчанию, когда тип, характеризуемый значением, содержит ссылочные типы, присваивание приводит к копированию ссылок. В результате вы получаете две независимые структуры, каждая из которых содержит ссылки, указывающие на один и тот же объект в памяти (т.е. "поверхностную копию"). Если вы хотите иметь "детальную копию", когда состояние внутренних ссылок полностью Копируется в новый объект, необходимо реализовать интерфейс ICloneable (это будет обсуждаться в главе 7).

Исходный код. Проект ValAndRef размещен в подкаталоге, соответствующем главе 3.

Оглавление книги


Генерация: 1.182. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз