Обработка исключений, оценка и глобальные обработчики ошибок в .Net - PullRequest
1 голос
/ 05 июля 2011

В .Net:

1) Разрешено ли исключение распространяться на глобальный обработчик ошибок, где вы оба регистрируете ошибку и показывает окно сообщения?Причина, по которой я спрашиваю, заключается в том, что если вы используете один глобальный обработчик ошибок для перехвата исключений сверху, вам понадобится куча Ifs, чтобы определить тип исключения и затем показать сообщение, которое может быть удобным (например, для filenotfound, файл, который выпри условии, что он не найден и т. д.)

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

2)Я ловлю только те исключения, с которыми могу справиться.Тем не менее, мое приложение имеет набор папок по выбору пользователя.Так как общий ресурс по умолчанию заблокирован, проверен и т. Д., Все отсутствующие файлы встречаются редко и поэтому являются «исключительным событием».Но когда пользователь выбирает местоположение на своем собственном компьютере, файлы могут отсутствовать, имена каталогов слишком длинные и т. Д. Я думаю, что это гораздо более распространенное явление, поэтому не стоит использовать здесь исключения.Но потом я уже упоминал, что сделал.Для такого рода конфликтов есть ли альтернативный способ структурировать мой код без дублирования?

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

Lasstly, что значит развернуть трассировку стека?

Спасибо}

Ответы [ 2 ]

1 голос
/ 05 июля 2011

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

Проработав с исключениями более 30 лет, я видел практически все механизмы и стили исключений, в том числе очень примитивные, а некоторые слишком «милые».Однако есть несколько общих принципов:

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

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

Что это говорит?Ну, обычно процедура, ближайшая к ошибке (т. Е. Та, что находится на «вершине» стека вызова-возврата), лучше всего «знает», какова причина ошибки, и лучше всего подходит для ее устранения.Но иногда (например, исключение «файл не найден») процедура, выполняющаяся ближе всего к точке исключения, не обладает достаточными знаниями для обработки ошибки (потому что, например, она не знает, где вызывающая сторона получила несуществующий файлимя или то, что содержимое файла должно было представлять).По этой причине, если текущая процедура не может обработать ошибку, она должна (неявно или явно) «повторно направить» ошибку вызывающей процедуре (и т. Д. Вниз по стеку вызова-возврата, пока не будет найдена процедура, которая хочет обработать ошибку).).Большинство схем исключений делают это «отставление» автоматически, хотя некоторые требуют, чтобы программист управлял им в определенной степени.

В конце концов, если ошибка не обрабатывается, вы попадаете в конец стека вызова-возврата.Это когда обработчик по умолчанию вступает во владение и решает, что делать (убить программу, возобновить с некоторой «безопасной» точки перезапуска в коде и т. Д.).Обработчик по умолчанию также, вероятно, попытается зарегистрировать ошибку (и содержимое стека возврата-возврата), чтобы ее можно было позже отладить.

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

Многие люди считают, что исключения должны использоваться только для обработки «катастрофических» ошибок, которые обязательно приведут по крайней мере к неприятному сообщению об ошибке пользователю, если не к полному завершению программы, но это представление совершенно неверно.Совершенно нормально использовать исключения для управления, скажем, недопустимым пользовательским вводом, и, на самом деле, обычно лучше использовать исключения с точки зрения «структурированного программирования», чем использовать коды возврата и тому подобное.Единственное предостережение заключается в том, что в некоторых средах исключения являются болезненно медленными и не должны использоваться там, где они могут возникать со значительной частотой.Но большинство новых сред более «просвещены», и в них исключения могут использоваться без особой заботы о производительности.

При использовании исключений нужно немного изменить стиль программирования.Самое главное, нужно позаботиться о том, чтобы структурировать код так, чтобы маркеры начала / конца для диапазона обработки исключений соответствовали началу и концу концептуальных операций, связанных с этим возможным исключением, и нужно быть уверенным, что любой код «возврата»необходимо отменить частично завершенную операцию в случае, если исключение соответствующим образом связано с этим диапазоном исключений (например, с предложением "finally" или, если язык не поддерживает это, в качестве отдельной подпрограммы, которая может быть вызвана изобработчик исключений для диапазона исключений).Но как только вы начинаете понимать такие вещи, восстановление после ошибок становится на намного, намного проще.

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

«Разматывание стека (трассировка)» может иметь несколько различных значений, но, как правило, когда исключение возникает в процедуре A, но повторяется через вызов- вернуть стек вызывающему A B, а затем, скажем, B вызывающему C, а обработчик исключений C «обрабатывает» исключение (не передает его вызывающему C), необходимо восстановить стек возврата-возврата в состояние, в котором онбыл во время выполнения C, так что C мог продолжить «нормальное» (более или менее) выполнение.Для этого записи для A и B в стеке будут (по крайней мере концептуально) «вытолкнутыми» или «раскрученными».Иногда (в зависимости от системы / языка) это «раскручивание» происходит, когда происходит «пульсация» необработанного исключения, но иногда этого не происходит, пока исключение не будет помечено как «обработанное».Обычно вам не нужно беспокоиться об этом, но некоторые системы или некоторые особые случаи могут потребовать знания об этом.

Также полезно отметить, что большинство систем создают содержимое стека возврата-вызова ввремя исключения доступно каким-либо образом для регистрации в качестве отладочной информации.Это чрезвычайно полезно, особенно при отладке «удаленных» ошибок, и стоит выяснить, как механизм работает в вашей системе.

0 голосов
/ 07 июля 2011

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

Рассмотрим, например, задачу чтения 'n' байтов из файла. Можно написать подпрограмму для чтения до 'n' байтов из файла и возврата количества прочитанных байтов (действительно, это была бы обычная парадигма без исключений). Попытка разобрать файл с помощью такой процедуры может раздражать. Считайте до 4 байтов, посмотрите, были ли прочитаны четыре байта, и если да, преобразуйте их в длинный, прочитайте до этого количества байтов, посмотрите, все ли ожидаемые байты были прочитаны, и т. Д. Необходимо проверить после каждого чтения, чтобы увидеть, он успешно получил все ожидаемые байты, быстро превращается в рутинную работу и затеняет то, что должен делать код. Альтернативный подход состоит в том, чтобы получить стандартное обещание, что он вернется, только если он успешно прочитал столько байтов, сколько было запрошено, и в противном случае выдает исключение. В таком случае более узкое обещание в процедуре чтения байтов устраняет необходимость тестов в коде, гарантирующих, что чтение завершено полностью и успешно.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...