
Объектно-ориентированное программирование.-7
.pdf
x1 == y1
ref x1 != ref y1
x2 = System.Object; y2 = System.Object
x2 == y2
ref x2 == ref y2
Итак, по умолчанию целые переменные равны нулю (и имеют соответствующее строковое представление), а строковое представление экземпляров класса System.Object содержит имя данного класса. Поэтому x1 = y1 и x2 = y2. Но экземпляры класса int хранят свои данные в разных ячейках памяти на стеке, поэтому и ссылки на них не совпадают. А экземпляры класса Object ссылаются на один и тот же объект.
И последний из рассматриваемых методов, пятый метод класса Object, возвращает метакласс типа. Метаданные – это данные о данных, а метакласс, соответственно – это класс, инкапсулирующий сведения о другом классе. О метаданных мы будем говорить в § 5.3.
Пока мы еще не изучили язык C# в степени, достаточной для написания таких программ. Поэтому можно просто взять готовый для изучения проект.
Пример: Samples\3.1\3_1_1_object.
3.1.2. Типы данных по значению
Отметим следующие особенности типов данных по значению:
1)Данные, как и в языке C++, хранятся на стеке;
2)Размещаются в памяти гораздо быстрее;
3)Автоматически удаляются при выходе из зоны видимости;
4)Только для данных фиксированной длины.
Типы по значению разделяются на простые типы, перечисляемые (Enum), обнуляемые (Nullable) типы и типы структуры. К простым типам от-
носятся целые типы (SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64),
типы с плавающей точкой (Single, Double, Decimal), логический (булев) тип (Boolean) и символьный тип (Char). Базовым классом для всех типов по значению является класс System.ValueType, который наследуется от System.Object (см. п. 3.1.5). Новых методов этот класс не объявляет, перегружая лишь некоторые методы базового класса (в т.ч. Equals и ToString). Однако, все производные от System.ValueType классы, представляющие собой типы данных по значению, реализуют интерфейсы IComparable,
81
IFormattable, IEquatable и IConvertible (см. п. 4.9.4), поэтому обладают неко-
торыми общими членами. Также в эти классы добавлены новые члены, присущие этим типам данных (табл. 3.3).
Табл. 3.3 – Общие члены типов данных по значению
Член |
Владелец(1) |
|
|
Описание |
|
|
|
|
|
|
|
|
|
|
Методы |
|
|
|
|
|
|
|
|
||||
int CompareTo(<тип> |
IComparable<T> |
Сравнивает данный экземпляр A |
||||
value) |
|
с заданным значением B (ре- |
||||
|
|
|||||
|
|
зультат отрицательный, если A |
||||
|
|
< B, ноль, если A = B и положи- |
||||
|
|
тельный, если A > B) |
|
|||
|
|
|
|
|||
int CompareTo(object |
IComparable |
То же, но без типизации |
|
|||
value) |
|
|
|
|
|
|
|
|
|
|
|
||
bool Equals(<тип> |
IEquatable<T> |
Возвращает |
истину, если |
дан- |
||
obj) |
|
ных экземпляр равен заданному |
||||
|
|
|||||
|
|
значению |
|
|
|
|
|
|
|
|
|||
override bool |
Object |
То же, но без типизации |
|
|||
Equals(object obj) |
|
|
|
|
|
|
|
|
|
|
|||
Type GetType() |
Object |
Возвращает метакласс типа |
|
|||
|
|
|
|
|
||
TypeCode |
IConvertible |
Возвращает |
TypeCode |
для |
||
GetTypeCode() |
|
типа |
(2) |
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
static <тип> |
|
Ряд методов для преобразования |
||||
Parse(string s, ...) |
|
строки в значение данного типа |
||||
|
|
|||||
|
|
|
|
|
||
override string |
Object |
Обратное |
преобразование |
– из |
||
ToString() |
|
данного типа в строку |
|
|||
|
|
|
||||
|
|
|
||||
string ToString |
IConvertible |
То же, но с дополнительными |
||||
(IFormatProvider |
|
опциями |
(региональные |
пара- |
||
|
|
|||||
provider) |
|
метры и т.д.) |
|
|
||
|
|
|
|
|||
|
|
|
||||
string |
|
То же, но в указанном формате |
||||
ToString(string |
|
|
|
|
|
|
format) |
|
|
|
|
|
|
|
|
|
||||
string |
IFormattable |
То же, но одновременно с фор- |
||||
ToString(string |
|
матом и дополнительными оп- |
||||
|
|
|||||
format, |
|
циями |
|
|
|
|
IFormatProvider |
|
|
|
|
||
|
|
|
|
|
|
|
provider) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
|
|
|
|
|
static bool |
|
Преобразование |
из |
|
строки в |
|||
TryParse(string s, |
|
значение данного типа с флагом |
||||||
..., out <тип> |
|
|||||||
|
успешного выполнения |
|
||||||
result) |
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
<тип> To<класс> |
IConvertible |
Преобразование |
к |
указанному |
||||
(IFormatProvider |
|
типу данных |
(3) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
provider) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Поля |
|
|
|
|
|
|
|
|
|
|
|
|
||||
const <тип> MaxValue |
|
Наибольшее |
возможное |
значе- |
||||
|
|
ние типа(4) |
|
|
|
|
|
|
const <тип> MinValue |
|
Наименьшее |
возможное |
значе- |
||||
|
|
ние типа(4) |
|
|
|
|
|
|
static readonly |
|
Представляет логическое значе- |
||||||
string FalseString |
|
ние false в виде строки |
(5) |
|
||||
|
|
|
|
|||||
|
|
|
||||||
static readonly |
|
Представляет логическое значе- |
||||||
string TrueString |
|
ние true в виде строки |
(5) |
|
||||
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
Примечания:
(1)Здесь и далее владелец – это класс, от которого данный класс наследует описываемый член, или интерфейс, член которого реализует данный класс;
(2)Перечисление TypeCode содержит коды типов объектов (табл. 3.4);
(3)Здесь <тип> – это тип данных, а <класс> – имя соответствующего ему класса .NET (например, класс Int16 – тип short);
(4)Отсутствует в классах System.Boolean и System.Enum;
(5)Только в классе System.Boolean.
Здесь и далее, если не оговорено другое, рассматриваются только открытые (public) члены классов, т.к. только к ним мы имеем доступ.
Табл. 3.4 – Символические константы перечисления TypeCode
Имя |
Значение |
Описание |
|
|
|
Empty |
0 |
Пустая ссылка |
|
|
|
Object |
1 |
Универсальный тип для представления любых ти- |
|
|
пов значений и ссылочных типов, которые не мо- |
|
|
гут быть представлены никаким другим значением |
|
|
TypeCode |
|
|
|
DBNull |
2 |
Значение null в базе данных |
|
|
|
|
|
83 |
Boolean |
3 |
Тип bool (System.Boolean) |
|
|
|
Char |
4 |
Тип char (System.Char) |
|
|
|
SByte |
5 |
Тип sbyte (System.SByte) |
|
|
|
Byte |
6 |
Тип byte (System.Byte) |
|
|
|
Int16 |
7 |
Тип short (System.Int16) |
|
|
|
UInt16 |
8 |
Тип ushort (System.UInt16) |
|
|
|
Int32 |
9 |
Тип int (System.Int32) |
|
|
|
UInt32 |
10 |
Тип uint (System.UInt32) |
|
|
|
Int64 |
11 |
Тип long (System.Int64) |
|
|
|
UInt64 |
12 |
Тип ulong (System.UInt64) |
|
|
|
Single |
13 |
Тип float (System.Single) |
|
|
|
Double |
14 |
Тип double (System.Double) |
|
|
|
Decimal |
15 |
Тип decimal (System.Decimal) |
|
|
|
DateTime |
16 |
Тип для представления значений даты и времени |
|
|
(System.DateTime), см. п. 3.1.2.6 |
|
|
|
String |
18 |
Тип string (System.String), см. п. 3.1.3.1 |
|
|
|
3.1.2.1. Целые типы
Список целых типов языка C# приведен в таблице 3.5.
|
|
|
|
Табл. 3.5 – Целые типы |
|
|
|
|
|
Тип |
Класс |
Описание |
|
Диапазон |
|
|
|
|
|
sbyte |
System.SByte |
8 бит |
|
–128…127 (–27…27–1) |
|
|
со знаком |
|
|
|
|
|
|
|
short |
System.Int16 |
16 бит |
|
–32 768…32 767 (–215…215–1) |
|
|
со знаком |
|
|
|
|
|
|
|
int |
System.Int32 |
32 бита |
|
–2 147 483 648…2 147 483 647 |
|
|
со знаком |
|
(–231…231–1) |
long |
System.Int64 |
64 бита |
|
–9 223 372 036 854 775 808… |
|
|
со знаком |
|
9 223 372 036 854 775 807 |
|
|
|
|
(–263…263–1) |
byte |
System.Byte |
8 бит |
|
0…255 (0…28–1) |
|
|
без знака |
|
|
|
|
|
|
|
ushort |
System.UInt16 |
16 бит |
|
0…65 535 (0…216–1) |
|
|
без знака |
|
|
|
|
|
|
|
|
|
|
84 |
|

uint |
System.UInt32 |
32 бита |
0…4 294 967 295 (0…232–1) |
|
|
без знака |
|
|
|
|
|
ulong |
System.UInt64 |
64 бита |
0…18 446 744 073 709 551 615 |
|
|
без знака |
(0..264–1) |
Как видно, каждый класс, описывающий тип, имеет более короткий псевдоним. Так, например, для описания 16-битного целого числа без знака, можно использовать тип ushort, UInt16 или System.UInt16.
Примеры описания целых переменных:
System.Int32 x; int y = 5;
ulong z = 0xfa12;
int n = new Int32(); // 0
В первой строке объявлена переменная x, являющаяся 32-битным целым со знаком. Она не инициализирована, поэтому попытка вызвать какиелибо методы класса System.Int32 или попытка присвоить x другой переменной вызовет ошибку компиляции:
n = x; // ошибка – использование локальной переменной, // которой не присвоено значение
Console.WriteLine(x.ToString()); // то же самое
Во второй строке объявляется переменная y такого же типа. Для ее инициализации используется константа 5. Переменная z, 64-битное целое без знака, инициализирована шестнадцатеричной константой. Как и в языке C++, такие константы начинаются с префикса «0x» или «0X». Переменная n инициализирована конструктором по умолчанию. Это эквивалентно инициализации нулем. Следующие варианты инициализации приводят к одинаковому результату:
int n1 = new System.Int32(); int n2 = new Int32();
int n3 = new int(); int n4 = 0;
Как и в C++, любая целая константа относится к типу int. При необходимости она неявно преобразуется к требуемому типу. Если необходимо явно указать тип целой константы, используются суффиксы:
123 – int
123U – uint
123L – long 123UL – ulong
Регистр суффиксов не важен, буквы U и L для типа ulong можно пере-
85

ставлять местами.
Однако, компилятор принимает во внимание значение самой константы. Так, константа 4000000000 будет иметь тип uint, т.к. ее значение выходит за пределы типа int. Если значение будет выходить за пределы типа uint, будет использован тип long, а если и его диапазона не хватит – ulong.
3.1.2.2. Типы с плавающей точкой
Список типов с плавающей точкой языка C# приведен в таблице 3.6.
Табл. 3.6 – Типы с плавающей точкой
Тип |
Класс |
Описание |
Диапазон |
|
|
|
|
float |
System.Single |
32 бита |
±1.5·10–45…±3.4·1038 |
|
|
7 значащих цифр |
|
|
|
|
|
double |
System.Double |
64 бита |
±5.0·10– |
|
|
15-16 значащих цифр |
324…±1.7·10308 |
decimal |
System.Decimal |
128 бит |
±1.0·10–28…±7.9·1028 |
|
|
28 значащих цифр |
|
|
|
|
|
Все, сказанное выше для целых типов данных, верно и для типов с плавающей точкой. Примеры описания переменных:
System.Single s = 12.3f; double d = 12.3;
decimal m = 12.3m;
Опять же, как и в языке C++, константа с плавающей точкой по умолчанию имеет тип double. Для указания другого типа данных используются суффиксы:
12.3 – |
double |
|
|
12.3F, |
12.3f |
– |
float |
12.3M, |
12.3m |
– |
decimal |
|
|
|
|
Для констант типа double тоже можно использовать суффикс (d или D), но это не обязательно. Так делают, чтобы показать, что целочисленная константа должна рассматриваться как константа с плавающей точкой. Однако, того же можно добиться, добавив ей ноль после десятичного разделителя:
Console.WriteLine(1 / 2); |
// 0 |
|||
Console.WriteLine(1 |
/ |
2d); |
// |
0.5 |
Console.WriteLine(1 |
/ |
2.0); // |
0.5 |
|
|
|
|
|
|
Если в приведенном выше примере описания переменных суффиксы не указать, то произойдет ошибка компиляции. Подробнее про явное и неявное
86

преобразование типов данных мы поговорим в п. 3.1.2.8.
Следует отметить, что для переменных с плавающей точкой доступен не весь диапазон значений – накладываются ограничения, связанные с количеством значащих цифр. Например, в переменной типа float может храниться значение 7,123456f (7 значащих цифр), а значение 7,1234567f (8 значащих цифр) – уже нет, одна цифра будет потеряна.
В типе decimal диапазон значений был уменьшен для увеличения количества значащих цифр. Т.е. больше бит отводится для мантиссы числа и меньше – для экспоненты. Чаще всего этот тип данных применяется для хранения денежных сумм.
Как известно, все числа хранятся в двоичной системе. Поэтому без погрешностей в памяти может храниться только такое нецелое число, которое является суммой степеней числа 2. Например, число 2,75 может быть сохранено без погрешности:
2,75 = 21 + 2–1 + 2–2,
а число 7,1 – нет. Убедимся в этом:
float f = 7.1f; double d = f; Console.WriteLine(f); Console.WriteLine(d);
При запуске этого кода на экране отобразятся числа:
7,1
7,09999990463257
Переменная d имеет больше значащих цифр, поэтому показывает, что на самом деле в переменной f хранится не число 7,1, а некое близкое к нему число. Число 2,75 в обоих случаях отобразилось бы одинаково.
Обратите внимание – при наборе текста программы разделителем целой и дробной части числа является точка, а при выводе на экран – символ, указанный в региональных настройках ОС. Подробнее об этом мы поговорим в § 3.2.
3.1.2.3. Логический тип
Логический тип данных представлен единственным типом (табл. 3.7).
Табл. 3.7 – Логический (булев) тип
Тип |
Класс |
Описание |
Диапазон |
|
|
|
|
|
|
87 |
|

bool |
System.Boolean |
8 бит, булево значение |
false, true |
|
|
|
|
В языке C++ многие типы данных могут быть неявно преобразованы к логическому типу. Например:
if (x)
{
// блок операторов
}
Данный код будет успешно компилироваться, если типом переменной будет bool, а также, если это будет указатель (на данные, на функцию или процедуру, на метод класса, класс, интерфейс – неважно), целый тип данных (языке C++ символьный тип также считается целым) или тип данных с плавающей точкой. Если значение переменной x равно 0 (NULL для указателей), то оно неявно преобразуется в значение false, во всех остальных случаях – в значение true. Однако, в языке C# более строгая типизация – данный код будет компилироваться только в том случае, если переменная x имеет тип bool:
int x;
if (x) // ошибка! неявное преобразование типа "int" в "bool"
//невозможно; явное тоже: при использовании (bool)x
//будет показана та же ошибка
{
// блок операторов
}
Для явного преобразования типов могут использоваться операции отношения либо специальные методы:
if (x != 0) // или if (!x.Equals(0))
{
// блок операторов
}
|
|
|
3.1.2.4. Символьный тип |
|
|
Символьный тип |
данных также представлен |
единственным типом |
|||
(табл. 3.8). |
|
|
|
|
|
|
|
|
|
Табл. 3.8 – Символьный тип |
|
|
|
|
|
|
|
Тип |
|
Класс |
|
Описание |
Диапазон |
|
|
|
|
|
|
char |
|
System.Char |
|
16 бит, символ Unicode |
U+0000…U+FFFF |
|
|
|
|
|
|
Символьные типы со знаком и без знака, т.е. signed char и unsigned char, имевшиеся в языке C++, в языке C# отсутствуют. Все символы пред-
88

ставляются как символы Unicode (UTF-16), представляющие собой двухбайтовые значения. Посмотреть, какой код соответствует каждому символу, можно в Таблице символов Windows (рис. 3.1).
Рис. 3.1 – Таблица символов Unicode
Открыть ее можно через меню «Пуск → Программы → Стандартные → Служебные → Таблица символов», или через меню «Пуск → Выполнить» (Win+R), набрав в нем «charmap». Далее следует в выпадающем списке наборов символов выбрать категорию Unicode.
Для инициализации переменных символьного типа можно использовать символьные литералы (как и в языке C++, заключенные в одинарные кавычки) или явное преобразование целых чисел к символьному типу:
System.Char a = 'A'; char b = (char)65; char c = '\u0041'; char d = '\x0041';
В символьных литералах также можно указывать код символа в шест-
89
надцатеричном виде с префиксом \x или \u. Все описанные переменные будут содержать большую латинскую букву A.
В настоящее время, кроме кодировки UTF-16, используются также UTF-8 и UTF-32. Первая из них позволяет уменьшить размер текста в байтах, если используются в основном символы из начала кодовой таблицы (U+0000… U+07FF). Использование второй обусловлено тем, что в настоящее время в кодировке Unicode имеется около 100 000 символов. Очевидно, что 16 бит для их представления недостаточно, поэтому был разработан стандарт UTF-32. При необходимости некоторые символы Unicode могут представляться последовательностью из двух значений типа char (т.е. 4 байтами). Кодировка UTF-8 может, теоретически, использовать до 6 байт для представления символа Unicode (см. ru.wikipedia.org/wiki, статья «Unicode»).
Также есть ряд специальных символов, впрочем, знакомых еще по C++
(табл. 3.9).
|
Табл. 3.9 – Специальные символы |
|
|
|
|
Символ |
Описание |
Код символа |
|
|
|
\' |
Одинарная кавычка |
U+0027 |
|
|
|
\" |
Двойная кавычка |
U+0022 |
|
|
|
\0 |
Конец строки |
U+0000 |
|
|
|
\a |
Звонок |
U+0007 |
|
|
|
\b |
Возврат (забой) |
U+0008 |
|
|
|
\f |
Следующая страница |
U+000C |
|
|
|
\n |
Переход на следующую строку |
U+000A |
|
|
|
\r |
Возврат каретки |
U+000D |
|
|
|
\t |
Горизонтальная табуляция |
U+0009 |
|
|
|
\v |
Вертикальная табуляция |
U+000B |
|
|
|
\\ |
Обратная косая черта |
U+005C |
|
|
|
Полный список управляющих символов можно посмотреть на сайте Википедии (ru.wikipedia.org/wiki) в статье «Управляющие символы».
Помимо тех членов, что описаны в п. 3.1.2, класс Char имеет несколько других полезных членов (табл. 3.10).
|
Табл. 3.10 – Специфические члены класса Char |
|
|
|
|
Член |
|
Описание |
|
|
|
static string |
|
Преобразует заданный символ Unicode |
|
|
|
|
90 |