Благодаря упаковке/распаковке программист не замечает разделения на ссылочные и размерные типы. И все же иногда нужно знать, с какими типами вы работаете. Ведь тонкие различия между этими двумя разновидностями типов могут оказать на приложение такое воздействие, которого вы никак не ожидали.
Вот пример. В следующем коде определен простой ссылочный тип (класс) Point и объявлены две ссылки: p1 и p2. Ссылка p1 указывает на новый объект типа Point, а при инициации ссылки р2 она приравнивается p1. Поскольку р1 и р2 больше, чем просто замаскированные указатели, их приравнивание не приводит к созданию копии объекта Point — копируется только адрес, Поэтому изменение одного экземпляра Point отражается на обоих объектах:
class Point
{
public int x;
public Int y;
}
.
.
.
Point p1 = new Point ();
pl.x = 1;
pl.y = 2;
Point p2 = p1; // Копируется лежащий в основе указатель.
р2.х = 3;
р2.у = 4;
Console. WriteLine ("p1 = ({0}, {1})", pl.x, р1.у); // Выводится "(3, 4)",
Console. WriteLine ("p2 = ({0}, {1})", р2.х, р2.у); // Выводится "(3, 4)".
Следующий фрагмент идентичен предыдущему, однако теперь Point — размерный тип (struct). Но в силу того, что приравнивание одного размерного типа другому вызывает создание копии последнего, результат получается совершенно иным.
Изменение одного экземпляра Point больше не влияет на другой:
struct Point
{
public int x;
public int y;
}
.
.
.
Point p1 = new Point ();
pl.x = 1;
pl.y = 2;
Point p2 = p1; // В стеке создается новая копия объекта,
р2.х = 3;
р2.у = 4;
Console. WriteLine ("p1 = ({0}, {1»", pl.x, pl.y); // Выводится "(1. 2)".
Console. WriteLine ("p2 = ({0}, {1}}", р2.х. р2.у); // Выводится "(3, 4)".
Иногда различия между ссылочным и размерным типами еще коварней.
К примеру, если Point является размерным типом, этот код совершенно корректен:
Point p;
р.х = 3;
р. У = 4;
Но если Point относится к ссылочному типу, та же последовательность команд даже не пройдет компиляцию. Почему? Потому что оператор:
Point p;
для размерного типа объявляет экземпляр, а для ссылочного типа — только ссылку на этот ссылочный тип. Ссылка подобна указателю — она непригодна, пока не инициализирована, например так:
Point p = new Point ();
Программисты с опытом работы на C++ особенно подвержены этим ошибкам, потому что, увидев оператор, объявляющий ссылку, они считают, что создается объект в стеке.
FCL — смесь размерных и ссылочных типов. Ясно, что иногда важно знать, с каким типом вы имеете дело. Как выяснить, к ссылочному или к размерному типу относится конкретный FCL-тип? Просто. Если в документации сказано, что это класс (например, «String Class*), то он относится к ссылочному типу. Если же сказано, что это структура (например, «Date Time Structure*), то это размерный тип. Помните о различиях, и вам удастся избежать утомительных часов отладки в попытках выяснить, почему ваш замечательный код дает непредсказуемые результаты.
Похожие статьи: