День шестьдесят четвёртый. #ЗаметкиНаПолях
Исключения. Продолжение
Советы по обработке исключений
1. Если блок
2. Программа может явным образом создавать исключения с помощью ключевого слова
3. Объём блока кода внутри
4. При отладке в Visual Studio для просмотра выброшенного исключения нужно добавить в окно Watch специальную переменную
5. Если обнаружится, что состояние приложения осталось испорченным даже после восстановительных операций в блоках
Приёмы работы с исключениями:
1. Активно используйте блоки finally для очистки ресурсов.
- В C# блоки
2. Не надо перехватывать все исключения.
- К примеру, код библиотеки не может знать, как он будет использоваться в различных приложениях. Исключение должно передаваться вверх по стеку вызовов и обрабатываться кодом приложения. Допустимо перехватывать исключения
3. Корректное восстановление после исключения.
- Иногда заранее известны типы исключений, источником которых может стать метод. Только полностью осознавая обстоятельства, вызывающие конкретные типы исключений, можно перехватывать их и позволять приложению продолжать работу после восстановления.
4. Отмена незавершённых операций при невосстановимых исключениях.
- Когда бизнес-логика требует отменить все ранее выполненные действия при возникновении исключения (банковская транзакция, сериализация группы объектов, транзакция в базе данных и т.п.), имеет смысл перехватывать ВСЕ возможные исключения, отменять сделанные изменения, но обязательно выбрасывать исключение повторно.
5. Скрытие деталей реализации для сохранения контракта
- Иногда бывает полезно после перехвата одного исключения, выбросить исключение другого типа для сохранения деталей реализации. Например, создать исключение
- При использовании этого приёма стоит перехватывать только те исключения, обстоятельства возникновения которых вы хорошо понимаете. Здесь мы обманываем вызывающий код сообщая неправду о том, что пошло не так, и о месте сбоя. Трассировка стека укажет только место выброса исключения
Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 20.
- https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/exceptions/
Исключения. Продолжение
Советы по обработке исключений
1. Если блок
catch
определяет переменную исключения, ее можно использовать для получения дополнительных сведений о типе созданного исключения. Эту переменную обычно стоит рассматривать как доступную только для чтения, однако можно добавлять нужную информацию в коллекцию её свойства Data
.2. Программа может явным образом создавать исключения с помощью ключевого слова
throw
.3. Объём блока кода внутри
try
зависит от управления состоянием. Если внутри блока вы собираетесь выполнить набор операций, каждая из которых может стать причиной исключения одного и того же типа, но при этом вы хотите обработать эти исключения по-разному, имеет смысл поместить операции в разные блоки try
.4. При отладке в Visual Studio для просмотра выброшенного исключения нужно добавить в окно Watch специальную переменную
$exception
.5. Если обнаружится, что состояние приложения осталось испорченным даже после восстановительных операций в блоках
catch
или finally
, имеет смысл его удалить, чтобы не создавать дополнительных проблем. Это делается методом AppDomain.Unload
. После этого приложение перезагружается, чтобы состояние инициализировалось нормально. Если состояние кажется настолько плохим, что имеет смысл завершить работу приложения, используйте статический метод Environment.FailFast
. Он завершает процесс без выполнения активных блоков try/finally
и без вызовов метода Finalize
.Приёмы работы с исключениями:
1. Активно используйте блоки finally для очистки ресурсов.
- В C# блоки
try/finally
автоматически создаются компилятором для некоторых конструкций: в lock
отключается блокировка, в using
вызывается метод Dispose
объекта, в foreach
вызывается метод Dispose объекта IEnumerator
, в деструкторах вызывается метод Finalize базового класса.2. Не надо перехватывать все исключения.
- К примеру, код библиотеки не может знать, как он будет использоваться в различных приложениях. Исключение должно передаваться вверх по стеку вызовов и обрабатываться кодом приложения. Допустимо перехватывать исключения
System.Exception
только при условии их повторной генерации в конце блока catch
.3. Корректное восстановление после исключения.
- Иногда заранее известны типы исключений, источником которых может стать метод. Только полностью осознавая обстоятельства, вызывающие конкретные типы исключений, можно перехватывать их и позволять приложению продолжать работу после восстановления.
4. Отмена незавершённых операций при невосстановимых исключениях.
- Когда бизнес-логика требует отменить все ранее выполненные действия при возникновении исключения (банковская транзакция, сериализация группы объектов, транзакция в базе данных и т.п.), имеет смысл перехватывать ВСЕ возможные исключения, отменять сделанные изменения, но обязательно выбрасывать исключение повторно.
5. Скрытие деталей реализации для сохранения контракта
- Иногда бывает полезно после перехвата одного исключения, выбросить исключение другого типа для сохранения деталей реализации. Например, создать исключение
RecordNotFoundException
для операций поиска в файле или базе данных и выбрасывать его вместо исключений типа FileNotFound
, IOException
или исключений, связанных с доступом к базе данных.- При использовании этого приёма стоит перехватывать только те исключения, обстоятельства возникновения которых вы хорошо понимаете. Здесь мы обманываем вызывающий код сообщая неправду о том, что пошло не так, и о месте сбоя. Трассировка стека укажет только место выброса исключения
RecordNotFoundException
, но не изначального. Это может затруднить отладку.Источники:
- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 20.
- https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/exceptions/