Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Объектно-ориентированное программирование.-7

.pdf
Скачиваний:
11
Добавлен:
05.02.2023
Размер:
4.54 Mб
Скачать

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