Концепция типа данных. Значащие (размерные) (Value type) и ссылочные (Reference type) типы данных. Упаковка и распаковка (Boxing, Unboxing).

Концепция типов данных состоит в том, что каждой информации приписывается тип, который описывается:

1) множеством допустимых значений типа,

2) набором операций для этого типа,

3) диапазоном допустимых значений,

4) количеством памяти, необходимой для хранения данного типа.

Значимые и ссылочные типы данных. Для значимых типов значение переменной (объекта) является неотъемлемой собственностью переменной (точнее, собственностью является память, отводимая значению, а само значение может изменяться). Для ссылочных типов значением служит ссылка на некоторый объект в памяти, расположенный обычно в динамической памяти — "куче". Объект, на который указывает ссылка, может быть разделяемым. Это означает, что несколько ссылочных переменных могут указывать на один и тот же объект и разделять его значения. К значимым типам относятся: логический, арифметический, структуры, перечисление. Массивы, строки и классы относятся к ссылочным типам

Будем называть целью левую часть оператора присваивания, а источником правую часть оператора присваивания. Поскольку источник и цель могут быть как значимого, так и ссылочного типа, то возможны четыре различные комбинации. Рассмотрим их подробнее.

• Цель и источник значимого типа. В этом случае источник и цель имеют собственную память для хранения значений. Значения источника заменяют значения соответствующих полей цели. Источник и цель после этого продолжают жить независимо. У них своя память, хранящая после присваивания одинаковые значения.

• Цель и источник ссылочного типа. В этом случае значениями источника и цели являются ссылки на объекты, хранящиеся в памяти ("куче"). При ссылочном присваивании цель разрывает связь с тем объектом, на который она ссылалась до присваивания, и становится ссылкой на объект, связанный с источником. Результат ссылочного присваивания двоякий. Объект, на который ссылалась цель, теряет одну из своих ссылок и может стать висячим, так что его дальнейшую судьбу определит сборщик мусора. С объектом в памяти, на который ссылался источник, теперь связываются, по меньшей мере, две ссылки, рассматриваемые как различные имена одного объекта. Ссылочное присваивание приводит к созданию псевдонимов — к появлению разных имен у одного объекта. Особо следует учитывать ситуацию, когда цель и/или источник имеет значение void. Если такое значение имеет источник, то в результате присваивания цель получает это значение и более не ссылается ни на какой объект. Если же цель имела значение void, а источник - нет, то в результате присваивания ранее "висячая" цель становится ссылкой на объект, связанный с источником.

• Цель ссылочного типа, источник значимого типа. В этом случае "на лету" значимый тип преобразуется в ссылочный. Двойственность существования значимого и ссылочного типа — переменной и объекта обеспечивается за счет специальных, эффективно реализованных операций, преобразующих переменную значимого типа в объект и обратно. Операция "упаковать" (boxing) выполняется автоматически и неявно в тот момент, когда по контексту требуется объект, а не переменная. При ее выполнении создается настоящий объект, хранящий значение переменной. Можно считать, что происходит упаковка переменной в объект.

• Цель значимого типа, источник ссылочного типа. В этом случае ссылочный тип преобразуется в значимый. Операция "распаковать" (unboxing) выполняет обратную операцию, — она "сдирает" объектную упаковку и извлекает хранимое значение.

Операции "упаковать" и "распаковать" (boxing и unboxing).

Все С#-типы, включая типы значений, выведены из класса object. Следовательно, ссылку типа object можно использовать в качестве ссылки на любой другой тип, включая типы значений. Если ссылку типа object заставляют указывать на значение нессылочного типа, этот процесс называют приведением к объектному типу (boxing). В результате этого процесса значение нессылочного типа должно храниться подобно объекту, или экземпляру класса. Другими словами, "необъектное" значение помещается в объектную оболочку. В любом случае приведение к объектному типу происходит автоматически. Для этого достаточно присвоить значение ссылке на объект класса object. Все остальное доделает С#.

Восстановление значения из "объектного образа" (unboxing) — это по сути процесс извлечения значения из объекта. Это действие выполняется с помощью операции приведения типа, т.е. приведения ссылки на объект класса object к значению желаемого типа. Пример:

int x =10; object obj; obj = x; // "Превращаем" х в объект.

int у = (int)obj; // Обратное "превращение" объекта obj в int-значение.

 

9. Концепция типа данных. Переменные и константы и их реализация в С#.

Концепция типов данных состоит в том, что каждой информации приписывается тип, который описывается:

1) множеством допустимых значений типа,

2) набором операций для этого типа,

3) диапазоном допустимых значений,

4) количеством памяти, необходимой для хранения данного типа.

Переменная — это экземпляр типа. Скалярную переменную можно рассматривать как сущность, обладающую именем, значением и типом. Имя и тип задаются при объявлении переменной и остаются неизменными на все время ее жизни. Значение переменной может меняться в ходе вычислений. Получение начального значения переменной называется ее инициализацией. Попытка использовать неинициализированную переменную приводит к ошибкам, обнаруживаемым еще на этапе компиляции. Объявление переменных:

int x, s; //без инициализации x=10; s=20; //отложенная инициализация

int y =0, u = 77; //обычный способ инициализации

int z= new int(); //допустимая инициализация в объектном стиле

Любой блок определяет область объявления, или область видимости (scope) объектов. Блок начинается открывающей, а завершается закрывающей фигурными скобками. Таким образом, при создании блока создается и новая область видимости, которая определяет, какие объекты видимы для других частей программы. Область видимости также определяет время существования этих объектов. Самыми важными в С# являются области видимости, которые определены классом и методом. Область видимости, определяемая методом, начинается с открывающей фигурной скобки. Но если метод имеет параметры, они также относятся к области видимости метода.

Как правило, переменные, объявленные в некоторой области видимости, невидимы (т.е. недоступны) для кода, который определяется вне этой области видимости. Таким образом, при объявлении переменной внутри области видимости вы локализируете ее и защищаете от неправомочного доступа и/или модификации. Эти правила области видимости обеспечивают основу для инкапсуляции.

int x; // Переменная х известна всему коду в пределах метода Main().

х = 10; if(х = = 10) { // Начало новой области видимости,

int у = 20; // Переменная у известна только этому блоку.

// Здесь известны обе переменные х и у. }

// у = 100; // Переменная у здесь неизвестна. // Переменная х здесь известна.

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

КонстантыC# могут появляться, как обычно, в виде литералов и именованных констант. Вот пример константы, заданной литералом и стоящей в правой части оператора присваивания: y = 7.7f; // константа типа float

Значение константы "7.7f" является одновременно ее именем, оно же позволяет однозначно определить тип константы. Заметьте, иногда, как в данном случае, приходится добавлять к значению специальные символы для точного указания типа. Синтаксис объявления: добавляется модификатор const, инициализация констант обязательна и не может быть отложена. Пример объявления констант:

const int SmallSize = 38, LargeSize =58; const int MidSize = (SmallSize + LargeSize)/2;

const double pi = 3.141593;