Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Основы объектно ориентированного программирования на языке С# базовые сведения о языке. Учебное пособие
.pdf
1.4. Строковый тип
Строковый тип в C# описывается ключевым словом string. В отличие
от C++, строка не является массивом символов (хотя у строки определена
индексация через квадратные скобки, возвращающая char) и не обязана
заканчиваться нулем. Строка является специальной структурой данных, в
которой хранится последовательность символов и дополнительная информация (длина этой строки). Константы строкового типа очень похожи на
C++, могут задаваться в двойных кавычках и содержать управляющие символы, начинающиеся с символа ‘\’, например, “\n” – конец строки. Сам
символ ‘\’ при этом должен удваиваться. Однако в C# есть и дополнительные возможности. Если поставить символ @ перед открывающими кавычками, то строка воспринимается «как есть». Например, операторы
string s1=”c:\\dir1”;
string s2=@”c:\dir1”;
определяют одинаковые строки. Символ кавычек для использования
внутри такой строки надо удвоить. С 11-й версии стандарта можно вместо @ использовать так называемые необработанные строковые литералы – тройные открывающие и закрывающие кавычки, и в этом случае
одинарные кавычки внутри строки не дублируются, а отступы при многострочном литерале можно регулировать закрывающими кавычками.
Еще более интересная возможность – интерполяция строк. Если перед
открывающими кавычками поставить символ ‘$’, то внутри строки можно
использовать почти любые выражения (включая переменные) в фигурных
скобках, и в строковую константу попадет значение выражения. Например, программа
Console.WriteLine($"PI={Math.PI}");
напечатает
PI=3.141592653589793
После выражения через запятую можно указать выравнивание результата и через двоеточие – формат вывода выражения, но более подробное
описание всех возможностей работы со строками не входит в наши планы,
обратитесь к справочной документации.
11

1.5. Тип object
В C# практически все типы могут быть приведены к типу object.
Переменной типа object можно присвоить значение любого другого
типа.
У object есть функция GetType, которая возвращает полную информацию о фактическом типе экземпляра. Более подробно об этом типе мы расскажем в п. 9.1.

2. ВЫРАЖЕНИЯ И ОПЕРАЦИИ
2.1. Арифметические выражения
Арифметические выражения в C# не имеют принципиальных отличий
от аналогичных выражений в других языках программирования, т. е. могут
содержать основные арифметические операции ‘+’, ‘–’, ‘*’, ‘/’, ‘%’
(соответственно сумма, разность, умножение, деление, деление по модулю), скобки, константы, переменные, функции. Приоритет операций
традиционный, т. е. сложение и вычитание имеют приоритет одинаковый,
но ниже, чем остальные операции. Как и во многих других языках, если
два операнда арифметической операции имеют разные типы, то при наличии возможности неявного преобразования «младший» тип приводится к
«старшему» и операция вычисляется для «старшего» типа. Для целых типов «старшим» является тип с бóльшим диапазоном представления, а если
в операции встречаются знаковый и беззнаковый типы, то выражение вычисляется для знакового типа следующего диапазона (если это возможно).
Например, выражение a * b, где переменная a имеет тип uint, а переменная
b – тип int, будет вычисляться для типа long. Если компилятор не может
определить старший тип, то требуется явное преобразование, например,
когда в выражении встретятся типы ulong и long.
Тип результата выражения – это тип, для которого вычислялась последняя операция.
Вещественный тип всегда является старшим для целого, double является старшим для float. Напомним, что вещественный тип decimal не может встречаться в одном выражении с другими вещественными типами без
явных преобразований.
Обратим внимание, что арифметические операции не определены отдельно для типов sbyte, byte, short и ushort, поэтому они перед выполнением операций преобразуются неявно к типам int или uint. При этом для
присвоения результата операции переменным исходных типов требуется
явное преобразование.
Для числовых типов определены унарные операции ‘+’ и ‘–’. При этом
результат этих операций при необходимости преобразуется к старшему
типу по аналогичным правилам, т. е. для sbyte, byte, short и ushort результат
будет иметь типы int или uint, применение унарного минуса к типу uint
дает результат типа long и т. д.
13

В языке C# для арифметических операций над целыми числами существует два режима – checked и unchecked. В режиме checked результат всех
действий проверяется на то, что он помещается в диапазон представления
соответствующего типа, и, если это не так, происходит исключение
OverflowException (что такое исключения и как их обрабатывать, мы объясним в разделе 3.10). В режиме unchecked никаких проверок на переполнение не происходит, арифметические операции выполняются аналогично
С++. Для переключения режимов глобально можно использовать опции
компилятора. Для явного указания режима можно использовать ключевые
слова checked и unchecked. Существует как операторы, так и выражения
checked и unchecked, например:
unchecked
{
int a = checked(b * b);
int c = b * b;
}
2.2. Побитовые операции
Как и в С++, в C# вводятся побитовые операции ‘&’, ‘|’, ‘^’, ‘~’
(конъюнкция, дизъюнкция, исключающее или (XOR), отрицание соответственно, отрицание – унарная операция). Правила приведения типов почти
те же, что и для арифметических операций, только отрицание беззнакового
типа, в отличие от унарного минуса, не переводит его в знаковый. Побитовые операции можно применять к типу bool (и в некоторых случаях к
типу enum).
2.3. Операции сравнения
Операции сравнения ‘<’, ‘>’, ‘>=’, ‘<=’, ‘==’, ‘!=’ (соответственно меньше, больше, больше или равно, меньше или равно, равно, не
равно) определены для всех основных типов (кроме object) традиционным
образом, результатом операции является логический тип bool, который, в
отличие от С++, не имеет неявного преобразования в арифметический тип.
14

2.4. Логические операции
Для типа bool определены логические операции ‘&&’, ‘||’, ‘!’
(конъюнкция, дизъюнкция, отрицание соответственно, отрицание – унарная операция). Операнды должны иметь тип bool, результат операции –
тип bool.
2.5. Операции сдвига
Операции левого и правого побитного сдвига ‘<<’ и ‘>>’ определены
для типов int, uint, long, ulong слева и числа битов count (целочисленного
типа) справа. Если число count превышает число битов сдвигаемого значения, то число битов сдвига определяется как count & 0x1f для типов int и
uint, или как count & 0x3f для long и ulong.

3. ОСНОВНЫЕ ОПЕРАТОРЫ
Операторы в C# могут начинаться в любом месте строки и, как правило, заканчиваются символом ‘;’. На число операторов в одной строке
ограничений нет, на длину строки ограничений тоже нет. Комментарий
может быть в конце любой строки, начало комментария – два символа ‘/’.
Начало многострочного комментария ‘/*’, конец – ‘*/’.
Операторы могут объединяться в блоки. Блок операторов начинается
символом ‘{’ и заканчивается символом ‘}’. Все операторы описания локальны для блока, т. е. переменная, описанная в блоке, не является описанной вне блока. Обратим внимание, что, в отличие от С++, C# не допускает
описание в блоке переменной с тем же именем, что и вне блока. Заметим,
что область видимости переменной в C# иногда зависит от способа ее
определения (например, при определении переменных с использованием
конструкций is в операторе if).
Как и в С++, в C# вводится понятие пространства имен namespace.
Оператор namespace имеет две формы. Первая форма, блочная, имеет вид
namespace <идентификатор пространства имен> {блок операторов}.
Все типы, объявленные внутри блока операторов, будут принадлежать заданному пространству имен, и при обращении к ним вне блока надо
будет явно указывать пространство (через символ ‘.’). Например,
namespace Example{ enum Color {RED, GREEN, BLUE}; }
фактически объявляет тип Example.Color.
Вторая форма оператора namespace имеет вид namespace <идентифи-
катор пространства имен> и действует до конца файла. Отметим, что
пространства имен могут быть вложенными. При этом вложенные операторы namespace N1{namespace N2{…}} можно заменить одним:
namespace N1. N2{…}.
Заметим, что вместо явного указания пространства имен можно использовать оператор using <имя пространства имен>, и тогда компилятор
будет пытаться найти имя типа во всех указанных в using пространствах
имен. Правда, если имя типа окажется в нескольких пространствах, компилятор всё равно попросит явно указать пространство. Кроме того, для
указания пространства имен может использоваться оператор global using,
действующий сразу на все файлы проекта.
16

3.1. Описание типа переменной
Оператор описания типа переменной состоит из названия типа и
списка переменных с возможной инициализацией значения. Например,
uint a = 0x80000001, b;
описывает две переменные: первую с явной инициализацией, вторую – без
нее. Заметим, что компилятор отслеживает, чтобы переменной было явно
присвоено какое-то значение перед первым ее использованием для чтения.
Переменные можно инициализировать значением по умолчанию (ключевое слово default) для своего типа. Например:
uint a=0x01, b=default;
Для арифметических типов значение по умолчанию ноль.
Идентификатор (имя переменной в данном случае) в C# не имеет ограничений на длину и, как и во многих языках, должен начинаться с буквы
и содержать буквы и цифры. Вот только понятие «буква» трактуется несколько шире, поскольку в идентификаторе можно использовать почти все
символы Unicode, например буквы кириллицы. Если очень хочется, чтобы
идентификатор совпадал с ключевым словом, то его нужно начать с символа ‘@’, например
uint @uint=0x01;
При этом компилятор будет считать, что переменная имеет имя uint (естественно, давать такие имена переменным нужно только в случае острой
необходимости). Символ подчеркивания также считается буквой.
В C# есть специальное ключевое слово var для описания типа переменной через выведение типа инициализирующего выражения. Это ключевое слово позволяет существенно упростить описание типов в тех случаях, когда тип имеет длинное сложное имя или тип значения выражения
трудно определить. Например, фрагмент программы
int a = 12;
uint b=0x01;
var c= a + b;
определяет переменную c типа long.
17

3.2. Операторы присваивания
Обычный оператор присваивания в C# выглядит традиционно: <переменная> = <значение> и ожидаемо присваивает переменной новое значе-
ние. Как и в С++, оператор присваивания одновременно является и выражением, значение которого можно использовать как-то еще, например,
присвоить еще одной переменной, поэтому вполне возможен оператор
c = a = b * 100;
Для упрощения синтаксиса оператора присваивания с целью изменения значения переменных вида
c = с + 100;
введены дополнительные операторы: ‘+ =’, ‘– =’, ‘* =’, ‘/ =’, ‘% =’,
‘& =’, ‘| =’, ‘^ =’, ‘< < =’, ‘> > =’, например:
c += 100;
В большинстве случаев действия дополнительных операторов присваивания вида c@=b полностью эквивалентны действию операторов вида
c=с@b, но иногда бывают и исключения, связанные с преобразованием
типов в выражениях. Например, если переменная a имеет тип byte, то оператор a += 2; корректно увеличивает ее значение на два, а оператор
a = a + 2; является синтаксической ошибкой, поскольку выражение справа
от оператора присваивания имеет тип int.
В наследие от С++ в C# остались еще и операторы инкремента и декремента ++ и – –, причем по два каждого типа – префиксный и постфиксный. Оператор инкремента увеличивает значение переменной на единицу,
а оператор декремента – уменьшает. При этом у префиксных операторов
значением оператора (если он используется как выражение) является измененное значение переменной, а у постфиксного – предыдущее. Например, после выполнения фрагмента
int a = 10;
int b = a++;
int c = ++a;
переменная а примет значение 12, b – 10, c – 12.
18

3.3. Условный оператор и условное выражение
Условный оператор имеет вид if (<выражение со значением типа
bool>) <оператор или блок операторов> else <оператор или блок операторов>. Блок else может быть опущен вместе с ключевым словом else.
Иногда вместо условного оператора можно использовать условное
выражение. Оно имеет вид <логическое выражение со значением типа
bool>?<выражение для истинного логического выражения>:<выражение
для ложного логического выражения>. Оба выражения, до символа ‘:’ и
после него, должны быть приводимы к типу результата условного выражения (который может определяться, например, типом переменной, которой присваивается выражение).
3.4. Оператор цикла с предусловием
Оператор цикла с предусловием имеет вид while (<выражение типа
bool>) <тело цикла (оператор или блок операторов)>. Условие продолже-
ния цикла проверяется на каждой итерации цикла перед его началом, цикл
заканчивается, если условие ложно. Если условие ложно до начала цикла,
цикл не выполняется совсем. В теле цикла могут встречаться специальные
операторы break – завершить цикл и continue – перейти к следующей итерации.
3.5. Оператор цикла с постусловием
Оператор цикла с постусловием имеет вид do <тело цикла (оператор
или блок операторов)> while (<выражение типа bool>). Условие продол-
жения цикла проверяется на каждой итерации цикла после его окончания,
цикл заканчивается, если условие ложно. Если условие ложно до начала
цикла, цикл выполняется хотя бы один раз. В теле цикла могут встречаться
специальные операторы break – завершить цикл и continue – перейти к сле-
дующей итерации.
3.6. Оператор цикла for
Оператор имеет вид for (<блок инициализации>; <условие продолжения>; <блок итерации>) <тело цикла (оператор или блок операторов)>.
При этом любой из блоков может быть пустым. Блок инициализации
выполняется один раз до начала цикла и предназначен для задания начального значения переменной цикла (и чаще всего для ее описания).
19

Если необходимо, через запятую можно инициализировать несколько
переменных. Например, синтаксически корректен оператор
for (int a = 9, b = 12; a < 10; a++) b--;
Условие продолжения – это логическое выражение типа bool , истинность которого позволяет продолжить итерации, выражение вычисляется
на каждой итерации перед ее началом (т. е. это цикл с предусловием).
Пустое условие продолжения считается истинным (т. е. организует
бесконечный цикл).
Блок итерации – оператор или несколько операторов и выражений,
разделенных запятыми, которые выполняются в конце каждой итерации
цикла. Заметим, что оператор for – это одно из редких мест в языке C#, где
в наследство от С++ остался оператор «запятая». Разделенные запятыми
операции выполняются одна за другой слева направо, результат выполнения предыдущей операции можно использовать в следующей (если он
присвоен какой-то переменной).
Как и в других операторах цикла, в теле цикла могут встречаться специальные операторы break – завершить цикл и continue – перейти к следующей итерации.
3.7. Операция is
К сожалению, эту операцию мы вынуждены привести до того, как читатель сможет понять механизм ее работы, но без нее сложно привести достаточно полную форму оператора switch. Предположим, у нас в программе есть переменная a, точный тип которой мы не знаем (как это в
принципе возможно, станет ясно в конце данного раздела). Логическая
операция is позволяет выяснить, какого типа эта переменная. Операция
имеет вид <переменная> is <тип>. Например, после выполнения фраг-
мента
int a = 10;
var b = a is double;
var c = a is int;
переменная b будет иметь тип bool и значение false, а переменная c – тип
bool и значение true. В современных версиях языка C# есть дополнитель-
ные синтаксические конструкции с операцией is (большинство из которых
20
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
