Обработка исключений и генерация исключений — это то, что я все время неправильно понимаю большинством разработчиков, с которыми я работал.
- Исключения позволяют находить ошибки в коде.
- Они останавливают текущую программу, чтобы предотвратить «ущерб» бизнесу.
- Они позволяют фильтровать между разумно ожидаемыми исключениями (сеть недоступна в мобильном приложении) и неожиданными исключениями ошибок, такими как NullReferenceException.
- Они сразу переходят к вопросу о том, почему произошла ошибка.
- Они позволяют каждому компоненту добавить слой информации о контексте и состоянии, чтобы облегчить отладку, это шаблон захвата, переноса и выброса.
Вы можете и должны использовать try/catch/(finally) почти везде, но...
Вы используете catch только в том случае, если знаете, какие исключения (исключения) могут возникнуть, и можете восстановиться после них. Вы редко должны перехватывать базовый тип Exception. Позвольте всем другим ошибкам всплывать и быть найденными программистом/тестером/пользователем.
Вы можете захотеть поймать базовый тип исключения, если собираетесь генерировать другое исключение и присоединять исходное исключение как InnerException.
Вы не должны дважды думать или лениться о создании собственных типов исключений. Например, вы можете написать DataAccessException и выдать его с исключениями, перехваченными в пределах уровня, присоединенного к InnerException. Таким образом, ваш журнал будет регистрировать тип исключения, который более точно показывает, где произошла ошибка, и вызывающий код может выбрать только перехват DataAccessException и выполнить повторную попытку или что-то в этом роде.
Вы также можете сделать DataAccessException абстрактным и создать подклассы для более конкретных исключений, таких как SqlDataAccessException или SecurityDataAccessException.
Как вы, кажется, знаете, вы используете finally, когда хотите убедиться, что какой-то код запускается в случае ошибки, даже если вы не перехватываете и не обрабатываете само исключение. В ситуациях, когда вы всегда должны освобождать ресурс, try/finally становится стандартным шаблоном.
Кроме того, по возможности поместите try/catch вокруг наиболее конкретного фрагмента кода, где вы можете обработать ошибку, позволяя ошибкам кода в окружающем коде вызывать сбой приложения.
Вы можете подумать: «Как я могу поймать конкретное исключение, если я еще не знаю, какие исключения будут сгенерированы?» Вы должны увидеть их задокументированными в методе ExecuteNonSql, и именно поэтому так важно документировать ваш собственный API/компонент с исключениями, которые он выдает. Для этого используйте XML-комментарии, а при отправке общедоступной библиотеки DLL включите генератор файлов XML-комментариев.
Может показаться, что это слишком много, но на практике это не так. Когда вы инвестируете в ведение журнала и правильную обработку/генерацию исключений, вы сможете устранять ошибки за считанные минуты, вы почувствуете себя чемпионом и скоро научитесь расстраиваться из-за плохого кода всех остальных :)
На этом этапе вашей жизни программиста я настоятельно рекомендую прочитать Руководство по проектированию фреймворка от Квалины и Абрамса. Это поможет вам быстро сделать правильный выбор во всех этих типах вопросов, и вы обнаружите, что использование собственного кода так же приятно, как и использование API Microsoft (в основном).
Люк
Добавлю немного о сообщениях. Я использую такие вещи в сообщении об ошибке.
"Невозможно {выполнить некоторую функцию}. Возник {тип исключения}. {Предложите совет по устранению или общие причины ошибки}. См. {внутреннее исключение|дополнительные записи журнала}".
Например, в компоненте для автосохранения состояния в приложении:
...
catch(FileNotFoundException fnfe)
{
string m = String.Format("Cannot save changes. A FileNotFoundException occurred. Check the path '{0}' is valid, that your network is up, and any removable media is available. Please see inner exception.", path);
_log.Error(m, fnfe);
throw new StorageLifecycleException(m, fnfe);
}
person
Luke Puplett
schedule
21.02.2013