Понятие значений и ссылок
Среда CLR поддерживает два способа представления данных — по значению (value) и по ссылке (reference). Главное различие между типом значения (value type) и ссылоч¬ным типом (reference type) — в способе хранения информации. Проблема с типами значения и ссылочными типами в том, что они являются техническим изобретением и не всегда понятны3.
Когда среда CLR запускает приложение, она создается поток выполнения инфра¬структуры общего языка (СП). Поток (thread) можно считать прогулкой по пассажу с покупкой разных мелочей. Вы гуляете сами по себе и можете покупать независимо от других людей. В магазинах много людей, выбирающих и покупающих различные вещи. Точно также компьютер имеет много потоков, выполняющих много разных не¬зависимых дел. Разгуливая по магазину, можно столкнуться с кем-нибудь из людей, и он уронит покупки. Хотя среда CLR пытается предотвратить такие ситуации, но если вы достаточно хорошо постараетесь, то ваш код сможет заставить другие потоки "уронить" покупки.
Во время выполнения поток имеет локальный пул памяти, называемый стеком (stack), своего рода бумажник, в котором хранится наличность и кредитные карточки. Вы носите бумажник с собой из одного магазина в другой, точно так же и поток перено¬сит свой стек от вызова от одного метода к другому. Когда вы заходите в магазин и не¬что приобретаете, у вас два главных способа платежа — наличными или по кредитной карточке. Но кредиткой нельзя расплатиться немедленно. Нужен аппарат, который об¬ратится к серверу, проверит наличие денег на счете, указанном кредитной карточкой, и выяснит, достаточно ли их для оплаты покупки. Платеж наличными намного быстрее платежа по кредитной карточке, поскольку вам не приходится вести переговоры с дис¬танционным компьютером.
Теперь предположим, что вы с супругой хотите оплатить покупки ценой 20 долл. Для этого вы оба могли бы использовать тот же банковский счет, имея для него две инди¬видуальные кредитные карточки. Но вы не можете проделать то же самое с наличным рас¬четом. Если у вас купюра в 10 долл., то ваша супруга не может использовать их совместно с вами. Ей понадобится вторая купюра в 10 долл., и вместе вы будете иметь 20 долл.
Наличный расчет и методы оплаты кредитной карточкой аналогичны передаче значения и ссылки. Наличный расчет — передача значения, а кредитная карточка — ссылки. Когда CLR выполняется, код переходит от вызова одного метода к другому, используя стек, который содержит ряд переменных типа значения. Значения таких переменных хранятся непосредственно в стеке подобно наличным деньгам. Значения ссылочных типов хранятся как указатели на участки память в стеке, точно так же как кредитная карточка, указывающая на наличные где-нибудь еще. Конкретный указатель указывает на ячейку памяти, называемой распределяемой памятью (heap). Эти концеп-ции иллюстрирует рис. 2.14.
Когда один тип значения присваивается другому, содержимое копируется. Если вы изменяете одну из копий, исходная не изменится. Когда вы изменяете значение ссылоч¬ного типа, то изменятся значения для всех, кто имеет указатель на него. Возвращаясь к примеру с кредитной карточкой и наличными, если вы с супругой имеете по 10 долл. и тратите из них 8, то это не повлияет на 10 долл., которые имеет ваша супруга, со¬гласно модели типов значения. Но если вы и ваш супруг имеете 10 долл. на общей кре¬дитной карточке, и вы потратите 8 долл., то на счете остается только 2 долл., согласно модели ссылочного типа.
Иногда имеет смысл использовать типы значений, иногда ссылочные типы, подоб¬но тому, как иногда имеет смысл платить наличными, а иногда — по кредитной кар¬точке. Кредитные карточки, как правило, вы используете при оплате дорогих товаров, поскольку вы не хотите носить для расчета большие суммы наличных. Это примени¬мо к типам значений и ссылочным типам, поскольку вы не захотите хранить большие типы значений в стеке.
Зная различие между стеком и распределяемой памятью, вы автоматически пони¬маете различие между типом значения и ссылочным типом, поскольку они связаны непосредственно. Типы значения обычно хранятся в стеке, а содержимое ссылочных типов всегда хранится в распределяемой памяти.