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

CSBasicCourse2ndedPodbelsky / CSBasicCourse2ndedPodbelsky

.pdf
Скачиваний:
32
Добавлен:
22.03.2016
Размер:
2.08 Mб
Скачать

процессе выполнения программы, делятся на две группы:

синхронные и

асинхронные.

Асинхронные ситуации возникают за счет внешних воздействий на программу,

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

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

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

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

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

Особых ситуаций, если они потенциально возможны, избежать нельзя. Но программист может предусмотреть в программе операторы для распознавания особой ситуации и для реакции на неё.

До появления механизма исключений реакция на особые ситуации зачастую была самой жесткой программа выдавала сообщение об ошибке и завершалась

аварийно. В лучшем случае, если особая ситуация возникла по вине пользователя,

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

Исключения позволяют отделить распознавание особой ситуации от реакции на неё. В механизме исключений есть два этапа генерация исключения и обработка исключения "исключения:обработка исключения" . Генерация исключения "исключения:генерация исключения" выполняется в том месте, где возникла и обнаружена особая ситуация, а обработка там, где это удобно в конкретном случае.

Если бы современные программы создавались по-старинке, без использования стандартных или специализированных библиотек (подпрограмм, процедур, функций,

классов), то без механизма исключений можно было бы обойтись. Более того,

прародитель Си-образных языков язык Си обходится без исключений. Но не будем упрекать в этом его авторов. При создании языка Си не был ещё внедрён в программирование объектно-ориентированный подход.

В настоящее время автор библиотечной функций или метода класса обязательно предусматривает операторы, распознающие особую ситуацию. Однако,

он не может предугадать как будет использована эта функция или метод программистом-пользователем.

Например, в библиотечном методе чтения данных из стандартного входного потока нельзя при ошибке в данных просто выдать сообщение пользователю

"повтори ввод!". Входной поток может быть настроен на текстовый файл и программа при этом выполняется без ввода данных с клавиатуры. Пользователь в этом случае не участвует в диалоге с программой.

Таким образом, распознавание особой ситуации в библиотечном методе должно быть "оторвано" от действий по устранению причин её появления. Эту возможность обеспечивают исключения.

RanException

Несоответствие размерностей

16.2. Системные исключения и их обработка

 

параметра и аргумента при вызове

В языке C# исключение это объект класса System.Exception "класс:

System.Exception" \y "класс" или производного от него класса. В пространство имен System входят кроме Exception ещё несколько классов исключений, которыми

можно пользоваться в программах. В таблице

16.1 приведены исключения из

пространства System, соответствующие особым ситуациям в программах на C#.

 

Таблица 16.1.

Классы системных исключений

ArgumentException

Недопустимое значение аргумента

при вызове метода

ArithmeticException

Базовый класс для исключений,

которые возникают при выполнении

арифметических операций. Например,

DivideByZeroException или

OverflowException.

ArrayTypeMismatchException

Посылается при попытке присвоить

элементу массива значение, тип

которого не совместим с типом

элементов массива.

DivideByZeroException

Посылается при попытке деления

на нуль целочисленного значения.

FormatException

Несоответствие параметров

спецификации форматирования

IndexOutOfRangeException

Посылается при выходе индекса

массива за пределы граничной пары

(индекс отрицателен или больше

верхней границы).

InvalidCastException

Посылается при неверном

преобразовании от базового типа или

базового интерфейса к производному

типу.

NullReferenceException

Посылается при попытке применить

ссылку со значением null для

обращения к объекту.

OutOfMemoryException

Посылается при неудачной попытке

выделить память с помощью операции

new. (Недостаточно свободной

памяти.)

OverflowException

Посылается при переполнениях в

арифметических выражениях, выполняемых в контексте, определенном служебным словом checked.

RanException

Несоответствие размерностей

 

параметра и аргумента при вызове

 

метода.

StackOverflowException

Посылается при переполнении

 

рабочего стека. Возникает, когда

 

вызвано слишком много методов,

 

например, при очень глубокой или

 

бесконечной рекурсии.

TypeInitializationException

Посылается, когда исключение

 

посылает статический конструктор и

 

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

 

(catch-блок) для перехвата

 

исключения

Исключения определены не только в пространстве имён System. В других пространствах имеются исключения, которые относятся к соответствующим разделам библиотек среды исполнения .NET. Например, в пространстве

System.Drawing.Printing имеются исключения, соответствующие особым ситуациям вывода на печать и т.д.

Исключение как объект создаётся с помощью специального оператора генерации (посылки) исключения:

throw выражение;

Однако этот оператор будет нами рассмотрен позже. Гораздо важнее сейчас научиться распознавать появление исключений и обрабатывать эти исключения.

Дело в том, что при выявлении особых ситуаций, методы библиотечных классов,

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

Достаточно часто начинающий программист наталкивается на исключения,

возникающие из-за неверного ввода данных при выполнении совершенно правильной программы. В качестве примера рассмотрим такой фрагмент кода

(программа 16_01.cs): double x; Console.Write("x = ");

x = double.Parse(Console.ReadLine()); Console.WriteLine("res = " + x);

Если пользователь в ответ на приглашение "x=" введёт, например, 3.3, то есть

допустит ошибку, отделив дробную часть вещественного числа не запятой, а точкой,

или введёт вместо цифры букву, то программа завершится аварийно и выдаст такое сообщение о необработанном исключении:

Необработанное исключение:

System.FormatException: Входная строка имела неверный формат.

вSystem.Double.Parse(String s)

Вэтом сообщении об исключении указано, что его источник метод

System.Double.Parse(string s).

Для перехвата и обработки исключений используется конструкция,

называемая блоком try/catch "блок: try/catch" . Она состоит из двух частей. Первая часть блок контроля "блок: блок контроля" за возникновением исключений представляет собой заключённую в фигурные скобки последовательность операторов языка C#. Перед открывающейся фигурной скобкой размещается служебное слово try "служебное слово: try" . Непосредственно за фигурной скобкой, закрывающей блок контроля за исключениями, размещается последовательность ловушек (иначе называемых обработчиками) исключений, а

также необязательный блок завершения "блок: завершения" (finally-блок). Каждый обработчик исключений "обработчик исключений" вводится служебным словом

catch "служебное слово: catch" . Имеется три формы catch-инструкции: catch (тип_исключения имя) {операторы}

catch (тип_исключения) {операторы} catch {операторы}

Входящий в catch-инструкцию блок операторов предназначен для выполнения действий по обработке полученного исключения.

Блок завершения имеет такой формат:

finally {операторы}

Операторы блока завершения выполняются в конце обработки каждого исключения. Точнее, блок finally выполняется всегда независимо от того, как поток управления покидает блок try.

В стандарте языка C# конструкция try/catch/finally называется try-оператором.

Определены три формы оператора try (даже если исключение не послано):

блок контроля, за которым следуют catch-обработчики (один или несколько);

блок контроля, за которым следует блок завершения (finally-блок);

блок контроля, за которым следуют catch-обработчики (один или несколько),

за которыми размещён блок завершения (finally-блок).

В качестве примера применения конструкции try/catch дополним приведённую выше программу, которая аварийно завершается при неверно введённых данных,

средствами для обработки исключений типа System.FormatException. Фрагмент кода

станет таким: double x;

while (true)

{

try

{

Console.Write("x = ");

x = double.Parse(Console.ReadLine()); Console.WriteLine("res = " + x);

}

catch (FormatException)

{

Console.WriteLine("Ошибка в формате данных!"); continue;

}

break;

}

В программу добавлен цикл, выход из которого возможен только при достижении конца тела цикла, где находится оператор break. В теле цикла блок

контроля за возникновением исключений, где размещены три оператора:

Console.Write("x = ");

x = double.Parse(Console.ReadLine()); Console.WriteLine("res = " + x);

Во втором из них возможна генерация исключения System.FormatException "исключение: System.FormatException" . Если оно появляется, то управление передаётся за пределы блока контроля (его третий оператор пропускается).

Ловушка (обработчик) исключений с заголовком catch (FormatException) настроена на обработку исключений типа FormatException. В теле обработчика два оператора.

Первый из них выдаёт на консоль сообщение, второй передаёт управление на начало следующей итерации цикла. Цикл не будет завершён, пока пользователь не введёт значение x без ошибок. Диалог пользователя с программой может быть, например,

таким:

x = 3.5<ENTER>

Ошибка в формате данных! x = 3d5<ENTER>

Ошибка в формате данных! x = 3,5<ENTER>

res = 3,5

Обратите внимание, что в блоке контроля за исключениями оператор

Console.WriteLine("res="+x); выполняется только один раз.

Порядок действий по контролю за возникновением исключений и их обработкой следующий. Выполняются операторы блока контроля за исключениями.

Если исключений не возникло, то все catch-обработчики пропускаются. При возникновении исключения управление незамедлительно передаётся catch–блокам.

Обработчики исключений просматриваются последовательно до тех пор, пока не будет обнаружен обработчик, "настроенный" на переданное исключение. После выполнения операторов этого обработчика выполняется блок завершения (если он есть) и только затем заканчивается исполнение try-оператора. Отметим, что среди блоков обработки выполняется только один или не выполняется ни один.

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

16.3. Свойства исключений

Каждое исключение это объект либо класса System.Exception, либо

производного от него. В классе Exception есть свойства, которые можно использовать при обработке исключений. Вот два из них:

Message "свойство: Message"

текстовое описание ситуации, при которой

создано исключение;

 

Source "свойство: Source"

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

исключение.

 

Прежде чем привести пример использования этих свойств, ещё раз обратимся к предыдущей программе, где использована catch-инструкция для FormatException.

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

врезультате ввода:

x= 1e999<ENTER>

произойдёт аварийное завершение программы с такой выдачей сообщения о необработанном исключении:

Необработанное исключение: System.OverflowException:

Значение было недопустимо малым или недопустимо большим для Double.

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

catch (OverflowException)

Более общим решением является дополнение программы catch–инструкцией,

настроенной на перехват всех исключений типа ArithmeticException, относящихся к обработке арифметических данных.

Чтобы получить доступ к свойствам перехваченного исключения, необходимо в заголовке catch-инструкции вслед за типом исключения поместить имя, которое будет представлять исключение в блоке обработки. Предыдущая программа с учётом сказанного может быть такой:

try

{

Console.Write("x = ");

x = double.Parse(Console.ReadLine()); Console.WriteLine("res = " + x);

}

catch (FormatException ex)

{

Console.WriteLine("ex.Message=" + ex.Message); Console.WriteLine("ex.Source=" + ex.Source); continue;

}

catch (ArithmeticException ex)

{

Console.WriteLine("ex.Message=" + ex.Message); Console.WriteLine("ex.Source=" + ex.Source); continue;

}

После блока try два обработчика. Второй перехватывает исключения типа

ArithmeticException к которым относится и OverflowException. В каждом из обработчиков выводятся значения свойств Message и Source, а затем управление с помощью операторов continue передаётся следующей итерации цикла. Результаты

выполнения программы могут быть такими: x = 1e999<ENTER>

ex.Message=Значение было недопустимо малым или недопустимо большим для Double. ex.Source=mscorlib

x = qwer<ENTER>

ex.Message=Входная строка имела неверный формат. ex.Source=mscorlib

x = 4.0<ENTER>

ex.Message=Входная строка имела неверный формат. ex.Source=mscorlib

x = 4,0<ENTER> res = 4

Обратите внимание, что сообщения (значения свойства Message) различны для разных типов исключений. Источник генерации исключений во всех примерах один

базовая библиотека Microsoft (mscorlib).

Примечание: При анализе исключения в catch-блоке полезно выводить значение выражения ex.ToString(). В нём содержится информация как о самом

исключении, так и о точке его генерации в коде программы

16.4. Управление программой с помощью исключений

В качестве примера применения механизма исключений не для исправления

ошибок ввода, а для управления программой, рассмотрим обработку исключения

System.IndexOutOfRangeException "исключение: System.IndexOutRangeException" .

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

изменяющий свои размеры в процессе выполнения программы.

Предварительно определим статический метод varyArray(), позволяющий изменять размер одномерного массива по следующим правилам. Параметры метода: ar – ссылка на исходный массив и размер int newSize нового массива, который будет сформирован методом. Если значение параметра newSize меньше длины исходного массива, то в получаемый массив копируются только newSize первых элементов исходного массива. Если newSize больше длины исходного массива, то значения всех элементов исходного массива присваиваются первым newSize элементам формируемого массива. Остальные элементы (как мы знаем) по умолчанию

инициализируются нулевыми значениями. Код метода: static int[ ] varyArray(int[ ] ar, int newSize) {

int [ ] temp = new int [newSize];

Array.Copy(ar, temp, newSize<ar.Length?newSize:ar.Length); return temp;

}

Этот закрытый метод будем использовать вначале для организации "роста"

массива, а затем для удаления из массива незаполненных при вводе правых

Соседние файлы в папке CSBasicCourse2ndedPodbelsky