Я стараюсь, чтобы мой ответ был таким же общим, как и вопрос;) но я могу предоставить некоторый код, если это необходимо.

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

try
{
   DoSomethingNotNice();
}
catch (ExceptionICanHandle ex)
{
   //Looking for examples of what people are doing in catch blocks
   //other than throw or wrapping the exception, and throwing.
}

заранее спасибо

 AaronLS12 янв. 2011 г., 22:13
Почему люди голосуют за то, чтобы закрыть это как оффтоп? Как это не связано с программированием? Какая тема подходит ему лучше, чем программирование?
 Hans Passant12 янв. 2011 г., 23:09
@ Аарон - Это похоже на то, как будто ты проезжаешь мимо автомобильной аварии и видишь кровь на лобовом стекле. Я иду "тьфу, эта бедная душа, что я могу поделатьэто«и тайно желая, чтобы я не видел это снова некоторое время. Несовершенная метафора, здесь мы можем проголосовать, чтобы изменить реальность! Но да, у ОП есть серьезное невыполнимое задание. Рад, что это не я. Держу пари, что вы рады». слишком.
 user16639013 янв. 2011 г., 00:39
Терпеть неудачу быстро может быть достаточно связанным, чтобы упомянуть.
 David Heffernan12 янв. 2011 г., 21:50
Вы вообще придумали какие-нибудь идеи?
 Greg12 янв. 2011 г., 21:58
Правило № 1 из 1:Не обрабатывайте исключения, если вы сначала не спросите меня

Ответы на вопрос(9)

что могло быть открыто для использования в попытке, и из-за исключения, которое было сгенерировано, не закрылось должным образом. Соединения с базой данных и доступ к файлам - это те, которые обычно требуют закрытия (хотя правильное использование блока using может справиться с этим)

Как только это будет сделано, вы можете использоватьthrow; бросить исключение на следующий уровень

В качестве альтернативы вы можете захотеть обернуть текущее исключение в новое исключение, более соответствующее текущему методу.

catch(LowLevelException ex){
     throw new HighLevelException("argh bad things happened!",ex);

}
 Ken Bloom14 янв. 2011 г., 18:41
@AaronLS, я отвечу в качестве примера. Предположим, вы создаетеDualCSVWriter класс, который открывает два файла в конструкторе, и всякий раз, когда вы передаете массивCSVWriter.writeRow функция, это пишет, что в виде строки CSV в обоих файлах. (Да, довольно странный интерфейс, но тем не менее ...) предположим, что один из файлов не открывается - вам нужно закрыть другой в конструкторе, но вы не хотите закрывать что-либо, если оба удастся. Здесь подходящее место для закрытия файлов будет вcatch блок.
 AaronLS14 янв. 2011 г., 20:53
@Ken Это возможно, но, возможно, дело в редизайне. Любой код, следующий за этой функцией, который пытается использовать эти файлы, становится более сложным, потому что он не знает, кто отвечает за закрытие файлов. Ваше условие публикации для этой функции противоречиво. Если вы вообще не закрываете файлы в случае успеха, это означает, что вы собираетесь продолжать использовать их после возврата из функции. Подумайте, если вы получили ошибку на одном и закрыли ее в перехватчике, тогда весь ваш код, следующий за этой функцией, должен будет условно проверить и снова открыть, если она закрыта.
 Ken Bloom14 янв. 2011 г., 16:40
@AaronLS: это зависит от того, были ли ресурсы предназначены для того, чтобы пережить время жизни вызывающей функции (например, вы выделяете ресурсы в конструкторе объекта, а объект предназначен для обеспечения фасада для работы с этими ресурсами). Тогда уместно убирать только перед лицом исключения.
 AaronLS14 янв. 2011 г., 18:35
@Ken Я обращался к его заявлению, что заявленные соединения и доступ к файлам должны быть закрыты в блоке catch. Итак, вы утверждаете, что закрытие их в блоке catch позволяет им пережить время жизни вызывающей функции? Это дало бы вам довольно существенные, независимо от того, произошло ли исключение.
 AaronLS12 янв. 2011 г., 22:11
Обычно освобождение файлов и соединений должно происходить в блоке finally, а не в блоке catch, или, альтернативно, в объявлении using, которое по существу использует блок finally для освобождения.

но MS рекомендует глобально обрабатывать ошибки в ядре .netпромежуточный слой.

Также вы можете использовать оператор switch какэто чтобы убедиться, что вы перебрасываете ошибки, которые вы не можете обработать.

Я стараюсь, чтобы мой ответ был таким же общим, как и вопрос;) но я могу предоставить некоторый код, если это необходимо.

что основная идея, лежащая в основе этого общего совета, состоит в том, чтобы избежать таких сценариев:

try
{
    SomeImportantResource = GetSomeImportantResource();
    SomeOtherImportantResource = GetSomeOtherImportantResource();
}
catch (Exception ex)
{
    SomeGlobalErrorHandlingMechanism(ex);
}

Я работал с разработчиками, которые, столкнувшись с ошибкой, просто обернули нарушающий код вtry/catch заблокировать и сказать: «Я исправил ошибку». Проблема в сценариях, подобных приведенному выше, состоит в том, что, просто перехватывая исключениеи не решая проблему, которая вызвала еговы можете подорвать основательность вашей программы. Выше, чтоcatch сделал это заставило нас сомневаться,SomeImportantResource а такжеSomeOtherImportantResource когда-либо были правильно инициализированы. Кажется вероятным, что в другом месте программы может быть код, которыйтребует для их инициализации, в этом случае, мы только что ввели ошибку путем «исправления» ошибки.

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

Или лучше, чем это: неловить исключение и сделать некоторую слабую попытку (или не попытку) «обработать» его; выяснить, что вызвало это и исправитьэто проблема. Очевидно, это невсегда возможно, но это возможно гораздо чаще, чем должно быть.

Решение Вопроса

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

По существу, существует правило, предотвращающее такие анти-паттерны, как:

try
{
   ...
}
catch(Exception ex)
{
   throw;
}

Улов здесь не делает ничего, кроме добавления скорости к разматыванию стека вызовов. Если вы на самом деле ничего не хотите, за исключением того, что ловите, вам даже не стоит беспокоиться об этом.

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

РЕДАКТИРОВАТЬ: Чтобы ответить на вопрос в посте, а не только в теме, вы можете написать правило следующим образом: «Не кодируйте оператор try-catch, который ничего не делает, или только отбрасывает перехваченное исключение. Все операторы catch должны выполнить какое-то дополнительное действие, относящееся к сгенерированному исключению. "

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

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

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

Основные правила отлова исключений:

Если вы не ожидаете исключения, не поймайте его.Если вы не можете или не хотите продолжать выполнение кода после получения исключения, знаете ли вы, что это может произойти, или нет, не отлавливайте его.Если вы ожидаете, что возникнет исключение, и знаете, как продолжить выполнение кода, когда оно произойдет (хотя бы на некоторое время), то перехватите и выполните любые специальные действия, которые вам необходимы для этого.НИКОГДА не ловить исключения (пустой блок catch); это заставляет приложения молча терпеть неудачу еще более непредсказуемыми способами.НИКОГДА не оставляйте catch-and-rethrow (блок catch только с rethrow) в рабочем коде. Иногда они могут быть полезны при отладке, так как позволяют идентифицировать определенные сегменты кода, которые дают сбой, но в производственном коде они представляют собой просто удар по скорости, который нужно выбросить или фактически справиться с исключением.
 KeithS13 янв. 2011 г., 22:00
Вы не должны проектировать исключения, бросая и ловя «счастливый путь» выполнения вашей программы. Исключения - только это; уведомление о том, что произошло что-то, что не соответствует вашим ожиданиям. Тем не менее, это неошибка пока ты не знаешь, что делать. Вот почему исключения могут быть пойманы вашей программой; это может быть ненормально, но вы все равно можете знать, что делать (что может быть чем-то иным, чем позволить среде выполнения или ОС прервать вашу программу). См. Выше некоторые общие примеры, касающиеся входа в SQL Server. Ни один из них не является нормальным, но вы можете попытаться продолжить в любом случае.
 KyleLib13 янв. 2011 г., 21:53
Да, AaronLS правильно. Большинство сценариев, с которыми я столкнулся, в конечном итоге приводит к тому, что я ловлю исключение, решая, следует ли украсить это исключение дополнительной информацией, заменяя исключение, чтобы скрыть конфиденциальную информацию, или повторно выбрасываю исключение и, в конце концов, очищаю в блоке finally, чтобы попытаться избежать коррумпированное государство. Почти все рекомендации / рекомендации, которые я прочитал, говорят, что не используют обработку исключений для нормальной обработки потока. Я думаю, что я ищу примеры, где я могу попытаться восстановить / отступить, не попадая в эту серую область «не использовать обработку исключений для управления потоком программы».
 AaronLS12 янв. 2011 г., 22:21
Я думаю, что он просит большего за конкретный пример ситуации, когда можно обработать исключение. Эти правила всегда пишутся более опытными людьми, которые сталкивались с этими ситуациями, и для человека, который никогда не сталкивался с ситуацией, когда они могут обработать исключение (потому что обычно вы их избегаете), трудно представить. См. «Доступно много информации о том, как / когда бросать, ловить, переносить исключения, но я ищу описание того, что должно происходить внутри блока catch, за исключением переноса и создания исключения».

есть ли у вас приложение, такое как OneNote, которое позволяет хранить ваши файлы на общем сетевом диске, но если сеть недоступна, то она временно использует локальное хранилище, пока не станет доступно основное хранилище.

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

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

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

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

Записать исключение и просто продолжитьПовторите то, что пошло не такПопробуйте другой способ сделать то, что вы пытались сделать

Все зависит от того, что пошло не так. Дело в том, что ловля и повторный бросок никому не нужны.

когда перехватываете исключение, которое некоторым образом полезно (например, выполнение блока кода, который будет выполнять функцию, предпринятую в операторе try, но делает это другим, но, возможно, менее эффективным способом, или просто информируя пользователя о том, что его действие не может быть выполнено), тогда вы должны поймать его и сделать это. Если вы просто регистрируете исключение, чтобы отследить проблему позже, вам следует повторно выбросить исключениеthrow; (НЕthrow ex;), если есть другой блок кода, который может обработать этот тип исключения.

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

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

которое не можете обработать, но вы можете ловить исключения, которые вымог бы уметь справляться:

try
{
   DoSomethingNotNice();
}
catch (ExceptionIMightBeAbleToHandle ex)
{
   if(iCanHandle(ex))
       thenHandle(ex);
   else
       throw;
}

Обратите внимание, что с помощьюthrow сам по себе должен сохранять информацию трассировки стека.

Типичные вещи, с которыми вы можете справиться изящно, были быFileNotFoundException.

Ваш ответ на вопрос