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

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

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

 

(число e)

 

 

const double PI

Отношение длины окружности к ее

 

диаметру (число π)

 

 

Примечания:

(1)Для типов sbyte, short, int, long, float, double и decimal;

(2)Для типов double и decimal;

(3)Для всех целых типов и типов с плавающей точкой;

(4)Различия в способах округления чисел представлены в табл. 3.20.

Табл. 3.20 – Сравнение методов округления чисел

 

–7.9

–7.1

7.1

7.9

 

 

 

 

 

Ceiling

–7

–7

8

8

 

 

 

 

 

Floor

–8

–8

7

7

 

 

 

 

 

Round

–8

–7

7

8

 

 

 

 

 

Truncate

–7

–7

7

7

 

 

 

 

 

Пример:

double angle = 30;

double rad = angle * Math.PI / 180;

Console.WriteLine("Угол {0}° в радианах составит {1} = pi/{2}", angle, rad, 180/angle);

Console.WriteLine("cos {0}° = {1}", angle, Math.Cos(rad)); Console.WriteLine("sin {0}° = {1}", angle, Math.Sin(rad));

Вывод на консоль:

Угол 30° в радианах составит 0,523598775598299 = pi/6 cos 30° = 0,866025403784439

sin 30° = 0,5

3.3.7.2. Генерация случайных чисел

Часто в математических вычислениях требуются случайные числа (для реализации различных стохастических алгоритмов, вариантов методов Мон- те-Карло, получения распределения Гаусса и т.п.). Для получения последовательностей псевдослучайных чисел в языке C# используются экземпляры класса System.Random.

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

191

Список членов класса Random приведен в табл. 3.21.

 

Табл. 3.21 – Члены класса System.Random

 

 

Члены

Описание

 

 

 

Конструкторы

 

 

Random()

Инициализирует новый экземпляр класса, номер по-

 

следовательности зависит от текущего времени (ана-

 

лог в языке C++ – randomize() или srand(gettime()))

 

 

Random(int Seed)

Инициализирует новый экземпляр класса с указанным

 

номером последовательности (аналог srand(seed))

 

 

 

Методы

 

 

int Next()

Генерирует следующее число последовательности

 

 

int Next(int

Для maxValue > 1 генерирует следующее число по-

maxValue)

следовательности в диапазоне [0, maxValue – 1]

 

 

 

int Next(int

Генерирует следующее число последовательности,

minValue, int

лежащее в диапазоне [minValue, maxValue – 1]

 

maxValue)

 

 

 

void NextBytes

Заполняет элементы указанного массива байтов слу-

(byte[] buffer)

чайными числами в диапазоне [0, 255]

 

 

 

double

Возвращает случайное число с плавающей точкой в

NextDouble()

диапазоне 0 ≤ x < 1

 

 

 

Пример:

 

Random rnd = new Random();

Console.WriteLine("10 случайных целых чисел в диапазоне [-100,100]:");

for (int i = 0; i < 10; i++)

{

Console.Write("{0} ", rnd.Next(-100, 101));

}

Console.WriteLine();

Вывод на консоль:

10 случайных целых чисел в диапазоне [-100,100]: 17 48 69 37 -14 84 -42 55 -64 88

192

§ 3.4. Операторы языка

Язык C# содержит множество операторов. Большинство из них будут знакомы разработчикам, имеющим опыт программирования на языках C и C++.

3.4.1. Основные понятия

Пример: Samples\3.4\3_4_1_csoper.

3.4.1.1. Операторы и блоки операторов

Операторы языка C# делятся на оператор объявления переменной, помеченный оператор и группу внедряемых операторов:

<оператор> :: <оператор объявления> <оператор> :: <помеченный оператор> <оператор> :: <внедряемый оператор>

Остановимся на них подробнее.

1) Оператор объявления переменной (§ 3.1):

<оператор объявления> :: <тип данных> <список переменных с инициализацией>;

2) Помеченный оператор (п. 3.4.4.3):

<помеченный оператор> :: <метка>: <оператор>

Все перечисленные ниже операторы являются внедряемыми. 3) Пустой оператор:

<пустой оператор> :: ;

4) Блок операторов:

<блок> :: "{" <список операторов> "}"

<блок> :: "{" "}"

Как видно, блок может быть пустым. Список операторов всегда заключается в операторные скобки «{}», за единственным исключением – в ветках оператора выбора (см. п. 3.4.2.2).

5) Оператор выражения (§ 3.3):

<выражение> :: <вычисляемое выражение>

6) Операторы управления ходом выполнения программы. Разбиты на три категории: операторы ветвления (п. 3.4.2), операторы цикла (п. 3.4.3) и

193

операторы перехода (п. 3.4.4). Во всех выполняется проверка вычисленного булевского значения, и на основе этой проверки изменяется ход выполнения программы. Также к данным операторам можно отнести операторы для работы с исключительными ситуациями (п. 3.4.5);

7) Операторы проверки переполнения. Как мы уже отмечали (см. п. 3.3.3.10), операторы checked и unchecked могут выступать как в роли операторов вычисления выражений, так и в роли операторов языка:

<оператор проверки переполнения> :: checked <блок> <оператор проверки переполнения> :: unchecked <блок>

8) Оператор блокировки (п. 5.2.3):

<оператор блокировки> :: lock (<выражение>) <внедряемый оператор>

9) Оператор управления ресурсами (см. п. 3.5.3):

<оператор выделения ресурсов> :: using (<оператор объявления>) <внедряемый оператор>

Требуется, чтобы переменные в объявлении обязательно были инициализированы, а тип данных реализовал интерфейс System.IDisposable.

Внедряемые операторы – это операторы, которые могут входить в состав других операторов языка. Здесь не рассматриваются еще два внедряемых оператора – unsafe и fixed. О них речь пойдет в § 5.5. Некоторые конструкции языка C# требуют использования внедряемых операторов, например, условный оператор if. Так, запись

bool x = true;

if (x) int i = 1; // Ошибка

будет вызывать ошибку компилятора, т.к. объявление переменной не является внедряемым оператором. С другой стороны, если объявление переменной заключить в блок или использовать только оператор выражения, ошибки не будет:

int j;

if (x)

{

int i = 1; // ОК

}

if (x) j = 1; // ОК

Другие операторы, например, checked и unchecked, требуют обязательного использования блока операторов:

194

uint k = 0;

checked k--; // Ошибка unchecked { k--; } // ОК

3.4.1.2. Конечные точки и достижимость

У каждого оператора языка имеется конечная точка – это позиция, непосредственно следующая за оператором. Когда управление достигает конечной точки оператора в блоке, оно передается следующему оператору этого блока.

Если существует возможность передачи управления оператору языка в ходе выполнения, говорят, что он является достижимым. И наоборот, если возможность выполнения оператора исключена, он называется недостижи-

мым.

Пример:

public static int Test()

{

const bool f = false;

if (f) Console.WriteLine("b = true!"); // Предупреждение goto x;

Console.WriteLine("Конец..."); // Предупреждение

x:return 0;

Console.WriteLine("...функции Test!"); // Предупреждение

}

Здесь все три метода WriteLine являются недостижимыми. Первый – потому что условие всегда ложно (f – константа), второй – потому что перед ним стоит оператор безусловного перехода, третий – потому что стоит после оператора возврата из функции.

Для недостижимых операторов компилятор C# выдает предупреждение «Обнаружен недостижимый код». В двух ситуациях достижимость конечной точки означает ошибку компиляции:

Достижимость конечной точки списка операторов ветки case в операторе switch. Обычно такая ошибка свидетельствует об отсутствии оператора break (см. п. 3.4.2.2).

Достижимость конечной точки метода, возвращающего значение. Обычно это свидетельствует об отсутствии оператора return (см. п. 3.4.4.4).

3.4.2. Операторы ветвления

Позволяют определить, когда и какой код выполнять. В языке C# предусмотрены два оператора выбора: switch, управляющий ветвлением про-

195

граммы на основе некоторого значения, и if, который выполняет код в зависимости от логического условия.

Пример: Samples\3.4\3_4_2_cond.

3.4.2.1. Условный оператор if

Выполняет блок операторов, если вычисленное им выражение имеет результат true. Синтаксис:

<условный оператор> ::

if (<логическое выражение>) <внедряемый оператор1> [else <внедряемый оператор2>]

true

логическое

false

 

 

 

выражение

 

 

 

 

 

 

 

 

 

 

 

 

 

внедряемый

 

внедряемый

оператор1

 

оператор2

 

 

 

 

 

 

 

 

 

 

 

 

а) с веткой else

true

логическое

false

 

выражение

 

внедряемый оператор1

б) без ветки else

Рис. 3.8 – Схема работы условного оператора

196

Как и в языке C++, ветка else является необязательной (рис. 3.8), а в качестве внедряемого оператора может, в свою очередь, использоваться другой условный оператор.

Если используются вложенные условные операторы, то оператор else будет относиться к ближайшему оператору if. Например, следующий код

if (логическое выражение1)

if (логическое выражение2) блок1 else блок2

else блок3

соответствует

if (логическое выражение1)

{

if (логическое выражение2) блок1 else блок2

}

else блок3

Возможен вариант с несколькими конструкциями else:

if (логическое выражение1) блок1

else if (логическое выражение2) блок2 else if (логическое выражение3) блок3 else ...

else if (логическое выражениеn) блокn else блокn+1

Это соответствует следующему коду:

if (логическое выражение1) блок1 else

{

if (логическое выражение2) блок2 else

{

if (логическое выражение3) блок3 else

{

...

else

{

if (логическое выражениеn) блокn else блокn+1

}

}

}

}

Пример:

int b;

Console.Write("Введите целое число: ");

if (int.TryParse(Console.ReadLine(), out b))

197

{

if (b < 0) Console.WriteLine("Вы ввели отрицательное число");

else if (b > 0) Console.WriteLine("Вы ввели положительное число"); else Console.WriteLine("Вы ввели ноль");

}

else

{

Console.WriteLine("Введено некорректное число");

}

3.4.2.2. Оператор выбора switch

Оператор switch выполняет список операторов, метка которого соответствует значению выражения выбора:

<оператор выбора> :: switch (<выражение выбора>)

"{"

<метка1,1> [<метка1,2> ...] <список операторов1> <метка2,1> [<метка2,2> ...] <список операторов2>

...

<меткаN,1> [<меткаN,2> ...] <список операторовN>

"}"

<оператор выбора> :: switch (<выражение выбора>) "{" "}"

<метка> :: case <константное выражение>: <метка> :: default:

Схема его работы приведена на рис. 3.9. Замечания:

1.Пустой блок оператора switch допустим, хотя компилятор выдает для него предупреждение «Пустой блок switch».

2.Выражение выбора должно иметь тип sbyte, byte, short, ushort, int, uint, long, ulong, char, string или перечисления, либо же должно иметь неявное преобразование в один из этих типов.

3.Константное выражение для ветки case должно иметь тип выражения выбора, либо неявное преобразование к этому типу.

4.Не допускается использование двух одинаковых меток. В противном случае компилятор генерирует ошибку «Метка уже встречалась в этом операторе выбора».

5.В списке операторов каждой ветки case конечная точка не должна быть достижима, иначе компилятор генерирует ошибку «Управление не может передаваться вниз от одной метки case к другой». Поэтому последним в списке должен быть оператор, не допускающий достижимость конечной точки, например:

• Оператор break, завершающий выполнение оператора switch;

• Оператор goto <метка>, осуществляющий переход на другую ветку:

198

goto case <константное выражение>; goto default;

номер ветки i = 1

false

ветка i

true

 

 

 

существует

 

 

выражение

true

выбора

 

[меткаi,1,

 

меткаi,2, …]

список операторовi

true

goto ветка

 

 

x

i = x

false

i = i + 1

false

Рис. 3.9 – Схема работы оператора выбора

199

Оператор goto <идентификатор>, осуществляющий безусловный пе-

реход (см. п. 3.4.4.3);

Оператор return, завершающий выполнение текущего метода (см. п.

3.4.4.4);

Оператор throw, передающий управление блоку обработки исключительной ситуации (см. п. 3.4.5);

Любая другая конструкция, исключающая передачу управления следующему оператору, например, бесконечный цикл или оператор continue, если оператор switch находится внутри цикла.

Пример:

static int Main()

{

DayOfWeek d = DayOfWeek.Friday;

switch (true) { } // Предупреждение switch (1.0) { } // Ошибка

switch (d)

{

default:

Console.WriteLine("Такого дня недели нет"); goto x;

case 1: // Ошибка

case (DayOfWeek)1: // ОК

Console.WriteLine("Понедельник"); break;

case DayOfWeek.Monday: // Ошибка

Console.WriteLine("Понедельник"); break;

default: // Ошибка

Console.WriteLine(); break;

case DayOfWeek.Thursday: // Ошибка

Console.Write("Четверг");

case DayOfWeek.Friday:

Console.Write("Пятница. А завтра будет... "); goto case DayOfWeek.Friday + 2; // Ошибка goto case DayOfWeek.Friday + 1;

case DayOfWeek.Saturday: case DayOfWeek.Sunday:

Console.WriteLine("Выходной день!"); break;

case (DayOfWeek)8: goto default;

200