Выбрать главу

Для большинства процедурных языков, реально используемых программистами — Паскаль, C++, Java, Visual Basic, С#, - система встроенных типов более или менее одинакова. Всегда в языке присутствуют арифметический, логический (булев), символьный типы. Арифметический тип всегда разбивается на подтипы. Всегда допускается организация данных в виде массивов и записей (структур). Внутри арифметического типа всегда допускаются преобразования, всегда есть функции, преобразующие строку в число и обратно. Так что, мой читатель, Ваше знание, по крайней мере, одного из процедурных языков позволяет построить общую картину системы типов и для языка С#. Отличия будут в нюансах, которые и придают аромат и неповторимость языку.

Поскольку язык C# является непосредственным потомком языка C++, то и системы типов этих двух языков близки и совпадают вплоть до названия типов и областей их определения. Но отличия, в том числе принципиального характера, есть и здесь.

Система типов

Давайте рассмотрим, как устроена система типов в языке С#, но вначале для сравнения приведу классификацию типов в стандарте языка C++.

Стандарт языка C++ включает следующий набор фундаментальных типов.

1. Логический тип (bool).

2. Символьный тип (char).

3. Целые типы. Целые типы могут быть одного из трех размеров — short, int, long, сопровождаемые описателем signed или unsigned, который указывает, как интерпретируется значение, — со знаком или без оного.

4. Типы с плавающей точкой. Эти типы также могут быть одного из трех размеров — float, double, long double.

Кроме того, в языке есть

5. Тип void, используемый для указания на отсутствие информации.

Язык позволяет конструировать типы.

6. Указатели (например, int* — типизированный указатель на переменную типа int).

7. Ссылки (например, doubles — типизированная ссылка на переменную типа double).

8. Массивы (например, char[] — массив элементов типа char).

Язык позволяет конструировать пользовательские типы

9. Перечислимые типы (enum) для представления значений из конкретного множества.

10. Структуры (struct).

11. Классы.

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

Эта схема типов сохранена и в языке С#. Однако здесь на верхнем уровне используется и другая классификация, носящая для C# принципиальный характер. Согласно этой классификации все типы можно разделить на четыре категории:

1. Типы-значения (value), или значимые типы.

2. Ссылочные (reference).

3. Указатели (pointer).

4. Тип void.

Эта классификация основана на том, где и как хранятся значения типов. Для ссылочного типа значение задает ссылку на область памяти в "куче", где расположен соответствующий объект. Для значимого типа используется прямая адресация, значение хранит собственно данные, и память для них отводится, как правило, в стеке.

В отдельную категорию выделены указатели, что подчеркивает их особую роль в языке. Указатели имеют ограниченную область действия и могут использоваться только в небезопасных блоках, помеченных как unsafe.

Особый статус имеет и тип void, указывающий на отсутствие какого-либо значения.

В языке C# жестко определено, какие типы относятся к ссылочным, а какие — к значимым. К значимым типам относятся: логический, арифметический, структуры, перечисление. Массивы, строки и классы относятся к ссылочным типам. На первый взгляд, такая классификация может вызывать некоторое недоумение, почему это структуры, которые в C++ близки к классам, относятся к значимым типам, а массивы и строки — к ссылочным. Однако ничего удивительного здесь нет. В C# массивы рассматриваются как динамические, их размер может определяться на этапе вычислений, а не в момент трансляции. Строки в C# также рассматриваются как динамические переменные, длина которых может изменяться. Поэтому строки и массивы относятся к ссылочным типам, требующим распределения памяти в "куче".