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

Основы объектно ориентированного программирования на языке С# базовые сведения о языке. Учебное пособие

.pdf
Скачиваний:
1
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
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
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]