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

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

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

case DayOfWeek.Tuesday:

while (true) // Здесь программа зациклится

{

Console.WriteLine("Вторник");

}

case DayOfWeek.Wednesday:

Console.WriteLine("Среда"); return 0;

case DayOfWeek.Thursday:

// Генерация исключительной ситуации throw new Exception("Четверг");

}

x: return 0;

}

3.4.3. Операторы цикла

Управляемые итерации, или циклы, в языке C# выполняют операторы while, do/while, for и foreach. В каждом случае исполняется внедряемый оператор, пока условие цикла является истинным. Однако, выполнение любого цикла может также быть прервано одним из операторов перехода (см. п.

3.4.4).

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

3.4.3.1. Оператор while

Синтаксис оператора while:

<оператор while> :: while (<логическое выражение>) <внедряемый оператор>

Схема работы оператора while приведена на рис. 3.10.

true

логическое

false

 

выражение

 

внедряемый

оператор

201

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

Пример:

int[] a = { 1, 15, 4, -2, 8, -6, -10 }; int i = 0;

int? neg = null;

while (i < a.Length)

{

if (neg == null && a[i] < 0)

{

neg = a[i];

}

i++;

}

if (neg == null) Console.WriteLine("В массиве нет отрицательных чисел"); else Console.WriteLine("Первое отрицательное число {0}", neg);

3.4.3.2. Оператор do-while

Иногда, когда требуется, чтобы тело цикла обязательно было выполнено хотя бы один раз, использование оператора while становится неудобным. В этом случае целесообразнее применять оператор do-while:

<оператор do-while> :: do <внедряемый оператор> while (<логическое выражение>);

Схема его работы изображена на рис. 3.11.

внедряемый

оператор

true

логическое

false

 

выражение

 

Рис. 3.11 – Схема работы оператора do-while

Пример:

Console.Write("Введите отрицательное число: "); neg = null;

202

do

{

if (int.TryParse(Console.ReadLine(), out i) && i < 0) neg = i; else Console.Write("Повторите ввод: ");

}while (neg == null);

3.4.3.3.Оператор for

Самый распространенный итерационный оператор. Синтаксис:

<оператор for> :: for ([<инициализатор>]; [<логическое выражение>]; [<итератор>]) <внедряемый оператор>

<инициализатор> :: <оператор объявления> <инициализатор> :: <выражение1> [, <выражение2>] [, ...]

<итератор> :: <выражение1> [, <выражение2>] [, ...]

Все три части цикла (инициализатор, логическое выражение, итератор) являются необязательными. При отсутствии логического выражения условие цикла всегда считается истинным.

Схема работы цикла for изображена на рис. 3.12.

инициализатор

true

логическое

false

 

выражение

 

внедряемый

 

 

оператор

 

 

итератор

 

 

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

Пример:

int[,] mas = { { 15, 22, -3, -1 }, { -4, 0, 8, 1 }, { 2, -11, 3, 14 } }; int[] vec = new int[mas.GetLength(0) * mas.GetLength(1)];

for (int odd = 0, k = 0; odd <= 1; odd++)

203

{

for (i = 0; i < mas.GetLength(0); i++)

{

for (int j = 0; j < mas.GetLength(1); j++)

{

if (Math.Abs(mas[i, j] % 2) == odd) vec[k++] = mas[i, j];

}

}

}

Console.Write("Четные и нечетные элементы матрицы: ");

for (i = 0; i < vec.Length; i++) Console.Write("{0} ", vec[i]); Console.WriteLine();

3.4.3.4.Оператор foreach-in

Вязыке C# есть специальный оператор для перечисления элементов коллекций – оператор foreach-in.

true

в коллекции

false

<выражение>

 

 

 

остались элементы

 

<идентификатор> = текущий элемент коллекции

внедряемый

оператор

Перейти к следующему элементу коллекции

204

Рис. 3.13 – Схема работы оператора foreach-in

Синтаксис:

<оператор foreach-in> :: foreach (<тип> <идентификатор> in <выражение>) <внедряемый оператор>

Замечания:

1.Тип выражения должен являться коллекцией, а тип идентификатора

типом элементов этой коллекции. Обычно коллекция – это класс или структура, реализующая интерфейс IEnumerable. Как создавать свои собственные коллекции, мы разберемся в § 4.9. В частности, рассмотренный нами ранее класс System.Array реализует данный интерфейс, поэтому цикл foreach можно применять для обработки любых массивов.

2.В качестве типа идентификатора можно использовать var, тогда тип будет определяться автоматически.

Схема работы цикла foreach-in изображена на рис. 3.13. Пример:

Console.Write("Все элементы матрицы: ");

foreach (int elem in mas) Console.Write("{0} ", elem); Console.WriteLine();

3.4.4. Операторы перехода

Мы можем управлять ходом исполнения программы с помощью одного из операторов перехода: break, continue, goto, return, throw и yield. Все эти операторы осуществляют безусловную передачу управления.

Замечание. Если оператор безусловного перехода break, continue, goto или return находится внутри блока try или catch (см. п. 3.4.5), и пытается передать управление в точку вне этого блока, то сначала выполняется код блока finally (если он есть), а уже затем осуществляется передача управления (см. пример ниже). Из самого блока finally передача этими операторами управления запрещена.

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

3.4.4.1. Оператор break

Прерывает текущий цикл или оператор выбора. После этого управление передается на строку кода, следующую за оператором цикла или оператора выбора. Синтаксис:

<оператор break> :: break;

205

Пример:

int[] a = { 1, 15, 4, -2, 8, -6, -10 }; int i = 0;

int? neg = null;

Console.WriteLine("Начинаем обработку массива...");

while (i < a.Length)

{

try

{

if (neg == null && a[i] < 0)

{

neg = a[i];

Console.WriteLine("Отрицательное число найдено.

Прерываем цикл...");

break;

}

}

finally

{

Console.WriteLine("{0}-я итерация цикла закончена...", i); i++;

}

}

if (neg == null) Console.WriteLine("В массиве нет отрицательных чисел"); else Console.WriteLine("Найдено число {0}", neg);

3.4.4.2. Оператор continue

Как и break, оператор continue позволяет изменять выполнение цикла. Но continue не завершает оператор текущего цикла, а прерывает текущую итерацию и передает управление на начало цикла для следующей итерации. Синтаксис:

<оператор continue> :: continue;

Пример:

Console.Write("Введите отрицательное число: "); neg = null;

do

{

if (!int.TryParse(Console.ReadLine(), out i) || i >= 0)

{

Console.Write("Повторите ввод: "); continue;

}

neg = i;

} while (neg == null);

206

3.4.4.3. Оператор goto

Оператор goto передает управление оператору, обозначенному меткой. Синтаксис:

<оператор goto> :: goto <идентификатор>;

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

Два последних варианта синтаксиса применяются в операторе выбора

(см. п. 3.4.2.2).

Первый вариант может применяться для перехода на любые помеченные операторы. Однако, если оператор goto вызывается вне области видимости метки, при компиляции возникнет ошибка. Таким образом, он не может применяться для перехода в другой метод или внутрь вложенного цикла, хотя выйти из вложенного цикла можно. В целом, использование этой формы оператора goto не рекомендуется. Он нарушает структурность программы и ухудшает ее читабельность. В языке C# достаточно других операторов, позволяющих обойтись без оператора безусловного перехода.

3.4.4.4. Оператор return

Оператор return определяет значение, возвращаемое исполняемым в данный момент методом, и приводит к немедленному возврату к вызывающему оператору. Синтаксис:

<оператор return> :: return [<выражение>];

Замечания:

1.Если метод ничего не возвращает (имеет тип возвращаемого значения void), то оператор return используется без выражения;

2.Если метод имеет тип возвращаемого значения, отличный от void, и не все ветви кода метода возвращают значение оператором return, компилятор генерирует ошибку. Исключение – использование оператора yield в итераторах (см. п. 3.4.4.6).

3.Тип выражения должен совпадать с типом возвращаемого методом значения, или иметь неявное преобразование к нему.

4.Как мы уже отмечали, если оператор return находится внутри блока обработки исключительной ситуации (try или catch), то сначала выполняется код блока finally (если он описан), а уже затем осуществляется возврат.

207

Пример:

static int Main()

{

try

{

Console.WriteLine("Завершаем выполнение программы..."); return 0;

}

finally

{

Console.WriteLine("...однако сначала будет выполнен блок

finally...");

Console.ReadKey(true);

}

}

3.4.4.5. Оператор throw

Оператор throw генерирует исключение. Синтаксис:

<оператор throw> :: throw [<выражение>];

Тип выражения должен быть классом System.Exception или его потомком. Подробности приведены в п. 3.4.5.

3.4.4.6. Оператор yield

Оператор yield используется для управления итератором (см. пример в п. 4.9.4.2). Синтаксис:

<оператор управления итератором> :: yield return <выражение>; <оператор управления итератором> :: yield break;

Замечания:

1.Допускается его использование только в методе, который не является анонимным, и тип возвращаемого значения которого реализует интерфейс IEnumerator<T>. Тип выражения должен совпадать с типом T или иметь неявное преобразование к этому типу;

2.Использование оператора yield в блоке finally влечет ошибку компи-

ляции;

3.Использование оператора yield return в блоке try-catch влечет ошибку компиляции;

4.Не допускается использование небезопасных блоков (unsafe);

5.Параметры итератора не могут иметь модификаторы ref или out.

208

3.4.5. Работа с исключительными ситуациями

Одно из основных назначений .NET CLR – недопущение ошибок (что достигается такими средствами, как автоматическое управление памятью и ресурсами в управляемом коде) или хотя бы их обнаружение во время компиляции (благодаря строго типизированной системе). Однако некоторые ошибки можно обнаружить только в период выполнения, а значит, для всех языков, соответствующих спецификации CLS, должен быть предусмотрен единый метод реакции на ошибки. Такой системой обработки ошибок, реализованной в CLR, является обработка исключительных ситуаций, или исключений. Работа с исключениями нам знакома еще по языку C++, однако, в нем она имеет ряд ограничений:

Использование исключений не является обязательным. Практически все стандартные функции языка C++ при возникновении ошибки не вызывают исключительных ситуаций, вместо этого они возвращают некоторое специальное значение (код ошибки, нулевой указатель и т.п.) или устанавливают некоторую глобальную переменную (флаг ошибки) в определенное состояние. При этом, если программа не проверяет этот флаг или возвращаемое значение, пользователь может не заметить ошибку. Не заметить исключительную ситуацию нельзя.

Исключения были разнородными объектами – структура exception в некоторых библиотеках C++, класс System::Exception в библиотеке VCL компании Borland и т.д. В итоге, централизованная обработка ошибок была затруднена.

Исключения – это условия, при которых нормальный ход программы невозможен или нежелателен. Когда вызов метода некоторого класса приводит к ошибке (индекс при работе с массивом не укладывается в диапазон, чтение данных из файла завершено неудачно и т.д.), то мы получаем об этом сообщение в виде исключения. Также мы сами можем генерировать исключительные ситуации и создавать свои собственные классы исключений.

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

3.4.5.1. Класс System.Exception

Все исключения должны иметь тип System.Exception (или производный от него). Полезные для нас члены класса Exception перечислены в табл. 3.22.

209

 

Табл. 3.22 – Члены класса System.Exception

 

 

 

Член

 

Описание

 

 

 

 

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

 

 

 

Exception()

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

 

ception с сообщением по умолчанию

 

 

Exception(string

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

message)

ception с указанным сообщением

 

 

 

Exception(string

Выполняет инициализацию нового экземпляра

message, Exception

класса Exception с указанным сообщением об

 

innerException)

ошибке и ссылкой на внутреннее исключение,

 

 

которое стало причиной данного исключения

 

 

 

 

 

Методы

 

 

 

 

 

 

virtual Exception

Возвращает

исключение,

которое является

GetBaseException()

причиной данного исключения

 

 

 

 

override string

Переопределенный метод

класс Object, воз-

ToString()

вращает строковое представление исключения

 

 

 

 

 

 

Поля

 

 

 

 

virtual string HelpLink

Ссылка на файл справки, связанный с этим ис-

 

ключением

 

 

 

 

int HResult

Кодированное числовое значение, присвоенное

 

исключению

 

 

 

 

 

Exception

Возвращает

экземпляр класса Exception, вы-

InnerException

звавший текущее исключение.

 

 

 

virtual string Message

Возвращает сообщение, которое описывает те-

 

кущее исключение

 

 

 

virtual string Source

Имя приложения или объекта, вызывавшего

 

ошибку

 

 

 

 

virtual string

Возвращает строковое представление фрагмен-

StackTrace

та стека вызова в момент возникновения ис-

 

 

ключения

 

 

 

 

MethodBase TargetSite

Возвращает метаданные метода, вызвавшего

 

исключение

 

 

 

 

 

 

Пример:

 

 

 

 

 

 

Exception e1 = new Exception();

 

 

Exception e2 = new Exception("Мое сообщение");

 

 

 

 

 

210