Не менее 6 вопросов: -)
Но с концепцией распространения исключения, это только то, что происходит, если у меня есть пустое предложение catch?
Исключение будет распространяться вверх, пока оно не будет перехвачено блоком перехвата вверх по стеку вызовов, который обрабатывает либо тип этого конкретного исключения, либо тип исключения ближе к базовому типу иерархии этого исключения. Так, например, все управляемые исключения происходят из System.Exception, поэтому блок перехвата, который перехватывает System.Exception, будет перехватывать каждое управляемое исключение.
Почему именно я хочу заключить исключение в более общее?
Я не уверен, что вы подразумеваете под "оберткой". Вы хотите перехватить исключение, заменить его другим и добавить оригинал в качестве свойства InnerException нового исключения? Или что-то еще?
Я думаю, что редко есть веская причина заменить исключение более общим исключением. Но вы, безусловно, можете заменить исключение другим исключением по одной или нескольким из трех причин:
- Чтобы скрыть детали реализации от вызывающей стороны.
- Чтобы улучшить уровень абстракции, чтобы он был более значимым для вызывающего.
- Чтобы создать пользовательское исключение, очень специфичное для рассматриваемой проблемы.
Кроме того, как бы я выбрал между переносом и заменой исключения?
Извините, но я все еще не понимаю, как вы определяете эти два как разные.
Является ли цепочка обработки исключений просто предложениями try и catch (или catchs)?
Вот основы того, что происходит, когда выдается исключение:
CLR последовательно проходит по списку блоков Catch в локальном блоке Try ... End Try, ища локальный блок Catch с фильтром исключений, совпадающим с выданным исключением.
Если в локальном блоке Catch есть фильтр исключений, соответствующий точному выброшенному исключению, выполняется код в этом блоке Catch, за которым следует код в блоке finally. Затем выполнение продолжается с первого оператора, следующего за конечной попыткой.
В качестве альтернативы, если сгенерированное исключение происходит из исключения, указанного локальным блоком Catch, происходят те же действия, что и описанные на втором шаге. Например, фильтр исключений, который перехватывает ArgumentException, также будет перехватывать исключения, полученные из ArgumentException, такие как ArgumentNullException, InvalidEnumArgumentException, DuplicateWaitObjectException и ArgumentOutOfRangeException.
Если ни один локальный блок Catch не соответствует сгенерированному исключению, CLR возвращается к стеку вызовов, метод за методом, ища блок Catch, который хочет ответить на исключение. Если в стеке вызовов не найдено соответствующего блока Catch, исключение считается необработанным.
В качестве альтернативы, если соответствующий блок Catch находится где-то в стеке вызовов, выполняется код в каждом блоке finally между броском и перехватом. Это начинается с элемента finally, принадлежащего блоку Try, в котором было сгенерировано исключение, и заканчивается параметром Final в методе ниже метода, в котором было обнаружено исключение.
После того, как эта очистка была завершена для всех методов ниже, где было обнаружено исключение, управление передается блоку Catch, который перехватил исключение, и этот код выполняется. Следующим запустится блок «Наконец» в «Попытке», где было обнаружено исключение Теперь, когда стек вызовов размотан и очистка от ошибок завершена, последний шаг - продолжить выполнение с первого оператора, следующего за конечной попыткой, на которой было обнаружено исключение.
Если код в блоке Catch вызывает другое исключение, исходное исключение автоматически добавляется к новому исключению с помощью свойства InnerException. Таким образом, исключения могут быть сложены без потери информации.
Не следует размещать код очистки в блоке finally, который может вызвать исключение, если только этот код не находится в своем собственном блоке Try. Без этой дополнительной защиты CLR ведет себя так, как будто новое исключение было сгенерировано после окончания после блока finally, и ищет в стеке вызовов удаленный блок Catch, который хочет ответить на новое исключение. Исходное исключение будет потеряно, если только исходный блок Catch не сохранил его.
Наконец, почему и как бы я хотел, чтобы исключение распространялось по стеку вызовов?
Почему: если вы не понимаете исключение и не знаете, как его исправить, вы должны позволить ему распространяться вверх.
Как: Улавливать только те типы исключений, которые вы понимаете и знаете, как их обрабатывать. Время от времени вам нужны детали любого исключения, чтобы сделать правильное восстановление. В этом случае вы можете поймать его, выполнить восстановление, а затем повторно выбросить его с помощью оператора throw; .
Также допустимо ли вставлять сложную логику обработки ошибок в блок catch (например, ifs / elses и тому подобное).
Как правило, да, потому что любое новое исключение, вызванное кодом в вашем блоке Catch, будет автоматически привязано к старому исключению через свойство InnerException. Но не стоит провоцировать этот механизм, если вы можете его избежать, поэтому чем проще будет ваш код, тем лучше. Еще одна веская причина, по которой ваш код Catch должен быть простым, состоит в том, что он часто не проходит ту же степень тестирования, что и основной код.