Суббота, 20.04.2024, 00:46
Приветствую Вас Гость | RSS

Лекции

Меню сайта
Форма входа
Категории раздела
ТАУ (Теория автоматического управления) [31]
лекции по ТАУ
Экология [151]
учебник
Бухгалтерский учет и налогообложение в строительстве [56]
Дементьев А.Ю. - Практическое пособие
Психология [104]
Пип
информатика [80]
с# Карли Ватсон
современные стулья [0]
новинки
Поиск

Главная » 2010 » Февраль » 11 » Обработка ошибок
00:20
Обработка ошибок
Обработка ошибок
Первая часть данной главы была посвящена способам поиска и исправления
ошибок в процессе разработки приложения, направленным на то, чтобы исклю-
чить их появление в окончательном варианте программы. Существуют, однако, си-
туации, когда заранее известно, что ошибки могут возникать, и способа добиться
100%-ной уверенности в их отсутствии не существует. В таких случаях рекоменду-
ется заранее предусмотреть возникновение проблем и написать такой код, который
мог бы аккуратно с ними справиться без прекращения выполнения приложения.
Обработка ошибок — это общее название всех способов такого рода; в данном
разделе будту рассмотрены возникновение исключительных ситуаций (exceptions)
и методы работы с ними.
Исключительные ситуации
Исключительная ситуация — это ошибка, возникшая либо в нашем коде, либо
в вызванной нашим кодом функции, которая проявилась в период выполнения.
В данном случае термин "ошибка" имеет более широкое значение, чем до сих пор,
поскольку исключительные ситуации могут создаваться в функциях и т. п. вручную.
Отладка и обработка ошибок 151
Например, мы можем создать исключительную ситуацию в функции в том случае,
если один из ее строковых параметров не начинается с символа "а". Строго гово-
ря, вне контекста настоящей функции это ошибкой не является, хотя с точки
зрения кода, вызывающего данную функцию, это, безусловно, ошибка.
Исключительные ситуации встречались нам несколько раз на протяжении этой
книги. Возможно, самым простым примером является попытка обратиться к эле-
менту массива, выходящему за его границы:
int[] myArray = {1, 2, 3, 4};
int myElem - my Array [4];
В результате появится приведенное ниже сообщение о исключительной ситуа-
ции, а выполнение приложения будет прекращено:
An unhandled exception of type 'System.IndexOutOfRangeException' occurred in </y/e>.exe
(Необрабатываемая исключительная ситуация типа
'System.IndexOutOfRangeException', возникшая в <файл>.ехе)
Здесь <файл> — это имя файла, в котором содержится данная исключительная
ситуация.
Исключительные ситуации описаны в пространствах имен, и большинство из
них обладает именами, из которых становится ясно, для чего они предназначены.
В приведенном примере возникшая исключительная ситуация имеет название
System. IndexOutOfRangeException ("исключительная ситуация: ' ВЫХОД Индекса ИЗ
диапазона допустимых значений"), что совершенно верно, поскольку мы задали
индекс, который не входит в диапазон допустимых значений для массива myArray.
Появление сообщения и завершение выполнения приложения происходит толь-
ко в тех случаях, когда исключительная ситуация является необрабатываемой.
А что требуется сделать для того, чтобы можно было "обработать" исключитель-
ную ситуацию?
try... catch.. .finally
В языке программирования С# предусмотрен специальный4 синтаксис для
Structured Exception Handling (SEH — структурированной обработки исключи-
тельных ситуаций). Существуют специальные ключевые слова, позволяющие по-
мечать участки кода как участки, в которых допустима обработка исключительных
ситуаций, и размещать инструкции, указывающие, что следует делать при возник-
новении исключительной ситуации. Для этих целей используются три ключевых
слова: try, catch и finally. Каждому из них соответствует некоторый блок кода,
и все они должны помещаться в последовательно расположенных строках кода.
Основная конструкция имеет следующий вид:
••; ., ••- ••:• ; - t r y •:. ./ " ' " . : : . ' • . • : - . •,; i ' • у , . ' ::•••';' " ч : ; ' . , • • .
Щ . • { ;'••?••;';, .. '-;'.. •••';";с C i v ? •'.:?.:.:. :?А- . , ;.•..•: • . :
> • : ' : . • • • • •.
catch {<ти1ШсключительнойСитуа.щш> Q) *
{ Ь ';• :; ; : " / •
> \ " ' ' •. ? щ ж ШШ: Й •
• / • . • •;. f i n a l l y •,:•••:•:' ••'•• •• \ • • . . ' : " . •••'••••' ^ • ' •
152 Глава 7
Существует также возможность использовать блоки try и finally без блока
catch, а также блок try с несколькими блоками catch. Если имеется один или
несколько блоков catch, то блок finally является необязательным, в противном
случае он обязателен.
Эти блоки используются следующим образом:
• try содержит код, который может привести к возникновению
исключительной ситуации.
• catch содержит код, который должен выполняться в случае
возникновения исключительной ситуации. Блоки catch могут быть
настроены таким образом, чтобы реагировать только на один
конкретный тип исключительной ситуации (например, на
System. IndexOutOfRangeException), ДЛЯ чего ИСПОЛЬЗуетсЯ параметр
<тилисключительнойСитуации>, поскольку существует возможность
одновременно установить несколько блоков catch. Но можно и вообще
опустить этот параметр, тогда получится общий блок catch, который
будет реагировать на все виды исключительных ситуаций.
• finally содержит блок кода, который выполняется всегда: либо после
выполнения блока try, если не возникло никаких исключительных
ситуаций, либо после блока catch, если производилась обработка
исключительной ситуации, либо непосредственно перед тем, как
приложение будет завершено из-за возникновения необрабатываемой
исключительной ситуации (последнее и объясняет необходимость
этого блока; в противном случае мы могли бы с тем же успехом
разместить этот код просто вслед за блоком).
События, происходящие после возникновения исключительной ситуации в бло-
ке кода try, имеют такую последовательность:
• Выполнение блока try прекращается в той точке,
в которой возникла исключительная ситуация.
• Если существует блок catch, то производится проверка
на предмет того, совпадает ли его параметр с типом возникшей
исключительной ситуации. Если блок catch отсутствует,
то выполняется блок finally (который в этом случае
является обязательным).
• Если блок catch существует, но значение его параметра
не совпадает с типом возникшей исключительной ситуации,
проверка производится в других блоках catch.
• Если параметр блока catch совпадает с типом возникшей
исключительной ситуации, то сначала выполняется код,
содержащийся в блоке, а затем — в случае, если он присутствует,—
ВЫПОЛНЯеТСЯ блок finally.
• Если ни один из блоков catch не соответствует типу возникшей
исключительной ситуации, то выполняется блок finally
(если он существует).
Давайте рассмотрим пример, демонстрирующий обработку исключительных си-
туаций.
Отладка и обработка ошибок 153
Практикум: запись текста в окно Output
1. Создайте новое консольное приложение с именем chO7ExO2
В директории C:\BegCSharp\Chapter7.
2. Внесите следующие изменения в программу:
class Classl
{
static string[] eTypes = {"none*, ''simple", "index", "nested index'};
static void Main(string[] args)
{ . . .
foreach (string eType in eTypes)
try
{
Console.WriteLine("Main() try block reached.");
Console.WriteLine("ThrowException(\"{0}\") called.'
ThrowException(eType);
Console.WriteLine("Main() try block continues.");
catch (System.IndexOutOfRangeException e)
// Line 18
eType);
// Line 19
// Line 21
// Line 23
Console.WriteLine("Main() System.IndexOutOfRangeException catch"
+ * block reached. Message:\n\"{0}\"", e.Message);
catch
{ . . ; ; . ..; , , . .., , ::\ ' ' '• • • • • ' • . • - '
Console.WriteLine{"Main() general catch block reached.");
}
finally
с •
Console.WriteLine("Main() finally block reached.");
}
Console.WriteLine(); / •
// Line 29
static void ThrowException(string exceptionType)
{
Console.WriteLine("ThrowException(\"{0}\") reached.", exceptionType);
//Line 43
switch (exceptionType)
{
case "none" :
Console.WriteLine("Not throwing an exception.");
break; . 7/ Line 48
case "simple" :
Console.WriteLine("Throwing System.Exception.");
throw (new System.Exception() ); // Line 51
• • : . : •-• - . ' break; • • • • •• . ' . . . : . •• • . . • : ••' ' : .: . : . . . . : , . . : .• •• .•• .• • • • ••• : '
case "index" : : •
Console.WriteLine("Throwing System.IndexOutOfRangeException.");
eTypes [4] = "error"; // Line 55
break;
case "nested index" :
try // Line 58
{
Console.WriteLine(*ThrowException(\"nested indexV) " +
"try block reached.");
Console.WriteLine("ThrowException(\"index\") called.");
ThrowException("index"); // Line 63
154 Глава 7
catch // Line 65
Console.WriteLine(*ThrowException(\"nested ,index\") general"
+ * catch block reached.") ;
••finally
Console.WriteLine("ThrowException(\"nested indexY") finally"
•••••. : . 4 ' . . + " b l o c k r e a c h e d . " ) ; ; ••- ; : -• •''::-:;: '
break;
3. Запустите приложение
(см. рис. слева).
Как это работает
У этого приложения имеется блок
t r y В фуНКЦИИ MainO, В KOTOpOM ВЫ-
ЗЫВаетсЯ функция ThrowExceptionO.
Названная функция может создавать
различные исключительные ситуации
в зависимости от того, какой параметр
используется при обращении к ней:
• ThrowException("none") —
не вызывает возникновения
исключительной ситуации.
• ThrowException("simple") —
вызывает возникновение
общей исключительной ситуации.
• ThrowException("index") — создает исключительную ситуацию
System.IndexOutOfRangeException.
• ThrowException("nested index") — содержит СВОЙ собственный
блок try, в котором располагается код, вызывающий
Thr owExc ep t ion ("index") с целью создания исключительной ситуации
System.IndexOutOfRangeException.
Все эти параметры обладают типом string и хранятся в глобальном массиве
eTypes, который в функции MainO проходится в цикле — для того, чтобы функция
ThrowExceptionO, была вызвана по одному разу с каждым возможным значением
параметра. В процессе выполнения этих итераций на консоль выводятся поясняю-
щие сообщения.
Этот пример предоставляет прекрасную возможность использовать метод по-
шагового выполнения программы, с которым вы уже познакомились. Проходя по
. всей программе строка за строкой, вы будете в точности понимать, каким образом
они выполняются.
Добавьте новую точку останова (со свойствами по умолчанию) в 18-ю строку
кода, которая выглядит следующим образом:
Console.WriteLine("MainO try block reached.");
Отладка и обработка ошибок 155
Обратите внимание, что номера строк используются
в том виде, в каком они появляются в загружаемой версии
программы. Если вывод номеров строк отключен, в него
можно войти с помощью пункта меню Tools | Options...
и раздела Text Editor] C# | General. Поскольку в вышеприведенный
код включены комментарии, вы можете пройти текст,
не имея перед собой открытого файла.
Запустите приложение в отладочном режиме.
Программа почти мгновенно перейдет в режим останова, при этом стрелка бу-
дет находится на 18-й строке. Если вы выберете вкладку Locals окна мониторинга
переменных, то увидите, что текущее значение етуре равняется "попе*. Восполь-
зуйтесь кнопкой Step Into для выполнения строк 18 и 19 и убедитесь в том, что
первая строка текста выведена на консоль. Далее используйте кнопку Step Into для
того, чтобы войти в функцию ThrowExceptionO на строке 20.
Внутри функции ThrowExceptionO (на строке 43) окно Locals претерпевает
определенные изменения. Теперь мы находимся вне области действия переменных
етуре и args (поскольку по отношению к Main о они являются локальными)
и вместо них видим аргумент exceptionType, значение которого равняется, естест-
венно, "попе". Продолжайте нажимать Step Into, и вы доберетесь до оператора
switch, в котором проверяется значение переменной exceptionType и выполняется
код, выводящий на экран строку "Not throwing an exception". После того как будет
ВЫПОЛНен оператор break на Строке 48, МЫ ВЫЙдеМ ИЗ функции ThrowExceptionO
и продолжим выполнение функции Main о со строки 21. Поскольку никакой иск-
лючительной ситуации не возникло, выполнение блока try будет продолжено.
Далее работа функции продолжается выполнением блока finally. Нажмите
Step Into еще несколько раз, чтобы завершить выполнение блока finally и первую
итерацию цикла foreach. Когда мы в следующий раз попадаем на строку 20, то вы-
зываем функцию ThrowExceptionO уже С другим параметром — "simple".
Продолжайте нажимать Step Into для дальнейшего продвижения по функции
ThrowExceptionO, и в конце концов вы доберетесь до строки 51:
throw (new System. Exception ()) ;
В данном случае, для создания исключительной ситуации используем ключевое
слово throw. В качестве параметра при нем стоит вновь (new) инициализируемая
исключительная ситуация. В данном случае мы используем еще один тип исключи-
тельных ситуаций ИЗ пространства имен System — System.Exception.
Выполнение этого оператора с помощью Step Into приводит к переходу в общий
блок catch, который начинается со строки 29. Поскольку в предшествующем бло-
ке catch, начинающемся со строки 23, совпадения не обнаружены, то вместо него
выполняется данный блок catch. Пошаговое выполнение позволяет пройти по всем
операторам этого блока, затем по операторам блока finally и вернуться на очеред-
ную итерацию ЦИКЛа foreach, В котором на строке 20 функция ThrowExceptionO
вызывается с очередным параметром. На этот раз параметр принимает значение
"index".
В этом случае функция ThrowExceptionO создает исключительную ситуацию
в строке 55:
eTypes[4] = "error";
Массив eTypes является глобальным, поэтому возможность доступа к нему суще-
ствует. Однако в этой строке кода делается попытка обратиться к пятому элементу
156 Глава 7
Wh«n lire глСе^Х) ti #\'&ж
Г g ^ ; **o the debugger
массива (не забудьте, что нумерация в массивах начинается с нуля), что приводит
К ВОЗНИКНОВениЮ исключительной Ситуации System. IndexOutOfRangeException.
На этот раз в функции Main о предусмотрен соответствующий блок catch,
и пошаговое выполнение программы приводит нас в начало настоящего блока на
строку 23.
Вызов console.writeLineо в этом блоке выводит сообщение, хранящееся
в описании исключительной ситуации посредством е.Message (мы обладаем досту-
пом к описанию исключительной ситуации через параметр блока catch). Дальней-
шее пошаговое выполнение программы через блок finally (но не через второй
блок catch, поскольку исключительная, ситуация уже обработана) снова приводит
нас к выполнению очередной итерации цикла и к очередному вызову функции
ThrowExceptionO на строке 20.
Когда МЫ достигаем КОНСТРУКЦИИ switch В функции ThrowExceptionO, TO ВХО-
ДИМ в новый блок try, который начинается со строки 58. При попадании на стро-
ку 63, ПРОИСХОДИТ ВЫПОЛНеНИе ВЛОЖеННОГО ВЫЗОВа фуНКЦИИ ThrowExceptionO —
на этот раз с параметром "index*. Если хотите, можете воспользоваться кнопкой
Step Over доя того, чтобы пропустить выполняемые здесь строки кода, поскольку
мы их уже проходили. Как и в предыдущий раз, этот вызов создает исключитель-
ную Ситуацию System. IndexOutOfRangeExcept ion. Однако теперь исключительная
ситуация обрабатывается во вложенной конструкции t r y . . .catch.. .finally, ко-
торая находится внутри функции ThrowExceptionO. В этой структуре отсутствует
явное совпадение с данным типом исключительной ситуации, поэтому его обработ-
кой занимается общий блок catch (начинающийся со строки 65).
Как и при обработке исключительных ситуаций в предыдущих случаях, мы
проходим в пошаговом режиме этот блок и соответствующий ему блок finally
и достигаем конца вызванной функции. Однако в данном случае имеется одно
принципиальное отличие: хотя исключительная ситуация и была создана, она так-
же была И Обработана — КОДОМ, нахОДЯЩИМСЯ В фуНКЦИИ ThrowExceptionO. Это
означает, что доя обработки в функции Main о исключительных ситуаций не оста-
лось, поэтому мы напрямую попадаем в блок finally, после чего приложение
завершает свою работу.
Просмотр списков и настройка
исключительных ситуаций
.NET Framework содержит огромное количество
типов исключительных ситуаций, и мы обладаем
полной свободой создавать и обрабатывать эти
исключительные ситуации в своих программах
и даже создавать исключительные ситуации для
обработки более сложными приложениями. VS
предоставляет специальный диалог (см. рис. слева),
позволяющий просматривать и редактировать име-
ющиеся исключительные ситуации, который можно
вызвать через пункт меню Debug | Exceptions... (или
нажатием комбинации клавиш Ctrl+Alt+E).
Исключительные ситуации выводятся в соответ-
ствии со своей категорией и пространством имен
библиотеки .NET. Исключительные ситуации,
ВКЛЮЧеННЫе В ПрОСТраНСТВО ИМеН System, МОЖНО
просмотреть, развернув сначала элемент Common
t<«;n:>».inr.!iif.ir.iHJtnm»riiTag!Tniin?tH
Motive RunTime Checks
Отладка и обработка ошибок 157
Language Runtime Exceptions, а затем элемент System. В открывшемся списке
МОЖНО Обнаружить ИСКЛЮЧИТельнуЮ Ситуацию System. IndexOutOfRangeException,
которую мы использовали ранее.
Любая исключительная ситуация может быть настроена с помощью переключа-
телей, расположенных в нижней части окна Exceptions. Большинство исключитель-
ных ситуаций по умолчанию имеют установку Use parent setting (использовать
установку более высокого уровня); это означает, что для них применяются опции
уровня всей категории (они полностью совпадают с изображенными на вышепри-
веденном рисунке). Первая группа переключателей, When the exception is thrown
(когда создалась исключительная ситуация), может использоваться для перехода
в отладчик даже в том случае, если исключительная ситуация уже обработана.
Вторая группа позволяет игнорировать необрабатываемые исключительные ситуа-
ции независимо от того, к каким последствиям это может привести.
В большинстве случаев установки по умолчанию нас вполне устраивают.
Замечания по поводу обработки
исключительных ситуаций
Обратите внимание на то, что блоки catch, предназначенные для более специ-
фической обработки исключительных ситуаций, необходимо располагать перед
блоками, предназначенными для более общей обработки. Если это требование не
будет выполнено, то приложение не пройдет компиляцию.
Также необходимо помнить, что мы можем создавать исключительные ситуации
непосредственно из блоков catch либо способом, использованным в предыдущем
примере, либо просто с помощью выражения:
throw;
Это выражение приведет к тому, что прерывание, уже обработанное блоком catch,
будет сгенерировано повторно.
Если исключительная ситуация будет создана с помощью throw, то она будет
обрабатываться не текущей конструкцией t r y . . .catch.. .finally, а конструкцией
более высокого уровня (хотя блок finally вложенной конструкции все равно вы-
полнится).
Если, например, внести следующие изменения в блок t r y . . .catch.. .finally,
расположенный В функции ThrowExceptionO:
try
Console.WriteLine("ThrowException(\"nested index\") *
"try block reached.•);
Console.WriteLine("ThrowException(\"index\") called.
ThrowException('index");
catch
Console.WriteLine("ThrowException(\"nested indexV) general"
+ " catch block reached. " ) ;
throw;
finally
Console.WriteLine("ThrowException(\"nested index\•) finally"
+ " block reached.");
158 Глава 7
то выполнение этой программы сначала продолжится выполнением блока finally,
изображенного здесь, а затем блока MainO, в котором будет обнаружено совпаде-
ние. В результате выходной поток изменится следующим образом:
Tlu«6u£xception<"nested ifidex"> called* .
ThrowException<"nested index"> reached.
ThrouException<"nested ir*dex*'> tin* block reached.
f!n*oi*Except:i.on<"iridex"> called,
IhrowException<"index"> reached.
Throwing System.IndexGutQIrRangreException. -
ThrotjException<"nested index*'> general catcli block, reached.
tbrouExcept'iotK''nested;;i«i4ex"> <f iria£$#.iblock reached- -: /-;:/ • ••• :'
MainO S^stei^.IndexOiAtOfBangeExceptioii catch bloclk reached. Me
"Exception of t^pe S»/stepi*lri€lexOutOfRa'ngeException was thrown
Ha in О .'finally .block;'reached.
Press &n$ key to continue
,
Итоги
На этом рисунке можно заметить дополнительные строки, выведенные из функ-
ции Main(), ПОСКОЛЬКУ исключительная Ситуация System.IndexOutOfRangeException
перехватывается именно в этой функции.
Эта глава посвящена преимущественно способам, позволяющим производить
отладку приложений. Таких способов несколько, и большинство из них доступно
независимо от типа создаваемого приложения.
Были рассмотрены следующие темы:
• Использование функций Debug.WriteLineO И Trace.WriteLine ()
для вывода текста в окно Output.
• Режим останова и способы перехода в него, включая
изменяемые точки останова.
• Окна в VS, содержащие отладочную информацию.
• Пошаговое выполнение программ.
• Обработка исключительных ситуаций с помощью
КОНСТРУКЦИИ t r y . . . c a t c h . . . f i n a l l y .
Теперь вы познакомились со всем, что может потребоваться для создания про-
стых консольных приложений, включая методы их отладки. В следующей части
этой книги мы перейдем к рассмотрению объектно-ориентированного программи-
рования.
Упражнения
1. "Использование функции Trace.writeLineO более предпочтительно,
чем Использование функции Debug.WriteLineO, ПОСКОЛЬКУ
второй вариант работает только при построении отладочной версии".
Согласны ли вы с этим утверждением? Почему?
Отладка и обработка ошибок 159
2. Напишите программу для простого приложения, в котором
содержится цикл, генерирующий ошибку после 5000 итераций.
Используйте точку останова для перехода в режим останова
непосредственно перед возникновением ошибки на 5000-й итерации.
(Подсказка: наиболее простой способ сгенерировать ошибку —
это попытаться получить доступ к несуществующему элементу массива,
например, к myArray[iooo] для массива, содержащего 100 элементов.)
3. "Блоки finally выполняются только в том случае, если
не выполняется блок catch". Верно ли данное утверждение?
4 . ВоСПОЛЬЗОВаВШИСЬ переЧИСЛИМЫМ ТИПОМ даННЫХ o r i e n t a t i o n ,
описанным ранее, напишите приложение, которое использует
Structured Exception Handling (SEH — структурированную обработку
исключительных ситуаций) для перевода переменной типа byte
в переменную типа orientation безопасным способом.
Обратите внимание, что вы можете форсировать возникновение
ИСКЛЮЧИТельНЫХ Ситуаций С ПОМОЩЬЮ КЛЮЧевОГО СЛОВа c h e c k e d ,
пример использования которого приводится ниже. Эту часть кода
вы должны использовать в своем приложении:
;" : ' - у - : : ' ; : . : : : ; : . ; : : : : : ; . ' х У - Щ - ^ ' ^ ••[ епшп orientation : byte
, . . . - . north = 1, : . .: •: '
: south = 2,
; • • •• ' • : , • : : - :
: - ; \ • , • : - ••• . e a s t ; = 3 , • •' • • •^•••' •• • : : • ; • •••-:•••••••• ••'. • , : . „
. ; . / : - : : . • : : - •' . • west = 4 • • • • • . . • •• • •
}
myDirection = checked((orientation)myByte);



































Категория: информатика | Просмотров: 1101 | Добавил: basic | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Календарь
«  Февраль 2010  »
ПнВтСрЧтПтСбВс
1234567
891011121314
15161718192021
22232425262728
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

krutoto.ucoz.ru
Бесплатный конструктор сайтов - uCoz