Я обычно согласен с большинством предупреждений анализа кода и стараюсь их придерживаться. Тем не менее, мне сложнее с этим:
CA1031: не перехватывать общие типы исключений
Я понимаю обоснование этого правила. Но на практике, если я хочу предпринять одно и то же действие независимо от выданного исключения, зачем мне обращаться с каждым из них конкретно? Кроме того, если я обработаю определенные исключения, что если код, который я вызываю, изменится, чтобы в будущем создать новое исключение? Теперь я должен изменить свой код для обработки этого нового исключения. Принимая во внимание, что, если я просто поймал, Exception
мой код не должен измениться.
Например, если Foo вызывает Bar, а Foo необходимо прекратить обработку независимо от типа исключения, выдаваемого Bar, есть ли какое-то преимущество в том, чтобы быть точным в отношении типа исключения, которое я перехватываю?
Может быть, лучший пример:
public void Foo()
{
// Some logic here.
LogUtility.Log("some message");
}
public static void Log()
{
try
{
// Actual logging here.
}
catch (Exception ex)
{
// Eat it. Logging failures shouldn't stop us from processing.
}
}
Если вы здесь не поймете общее исключение, то вам придется перехватывать все возможные типы исключений. У Патрика есть хорошая точка зрения, с которой OutOfMemoryException
не следует разбираться. Так что, если я хочу игнорировать все исключения, кроме OutOfMemoryException
?
источник
OutOfMemoryException
? Такой же код обработки, как и все остальное?OutOfMemoryError
, который отделен отException
дерева наследования по той же самой причинеОтветы:
Эти правила, как правило, являются хорошей идеей и поэтому должны соблюдаться.
Но помните, что это общие правила. Они не охватывают все ситуации. Они охватывают самые распространенные ситуации. Если у вас есть конкретная ситуация, и вы можете сделать аргумент, что ваша техника лучше (и вы должны быть в состоянии написать комментарий в коде, чтобы сформулировать свой аргумент для этого), тогда сделайте это (и затем пересмотрите его).
На встречной стороне аргумента.
Я не вижу ваш пример выше как хорошую ситуацию для этого. Если система журналирования не работает (возможно, регистрируется какое-то другое исключение), то я, вероятно, не хочу, чтобы приложение продолжало работу. Выйдите и распечатайте исключение для вывода, чтобы пользователь мог видеть, что произошло.
источник
Да, ловить общие исключения - это плохо. Исключение обычно означает, что программа не может делать то, что вы просили.
Есть несколько типов исключений, которые вы можете обработать:
Да, и как правило: если вы не знаете, что делать с исключением, если вы его поймаете, лучше просто быстро потерпеть неудачу (передайте исключение вызывающей стороне и дайте ему обработать это)
источник
У самой верхней внешней петли должен быть один из них, чтобы напечатать все, что он может, а затем умереть ужасной, насильственной и ШУМНОЙ смертью (поскольку этого не должно произойти, и кто-то должен услышать).
В противном случае вы, как правило, должны быть очень осторожны, так как вы, скорее всего, не ожидали всего, что может произойти в этом месте, и, следовательно, скорее всего, не будете относиться к нему правильно. Будьте настолько конкретны, насколько это возможно, чтобы вы поймали только тех, кого, как вы знаете , случится, и пусть те, кого не видели раньше, всплывают до упомянутой выше шумной смерти.
источник
Дело не в том, что это плохо, а в том, что конкретные уловы лучше. Когда вы конкретны, это означает, что вы на самом деле понимаете, более конкретно, что делает ваше приложение, и имеете больший контроль над ним. В общем, если вы столкнетесь с ситуацией, когда вы просто поймаете исключение, зарегистрируете его и продолжите, вероятно, в любом случае происходят какие-то плохие вещи. Если вы специально перехватываете исключения, которые, как вы знаете, могут генерировать блок кода или метод, то существует большая вероятность, что вы сможете на самом деле восстановить их, вместо того, чтобы просто регистрировать и надеяться на лучшее.
источник
Две возможности не являются взаимоисключающими.
В идеальной ситуации вы должны перехватывать все возможные типы исключений, которые может генерировать ваш метод, обрабатывать их для каждого исключения и, в конце концов, добавлять общее
catch
предложение для перехвата любых будущих или неизвестных исключений. Таким образом, вы получите лучшее из обоих миров.Имейте в виду, что для того, чтобы поймать более конкретные исключения, вы должны поместить их в первую очередь.
Изменить: По причинам, указанным в комментариях, добавлен пересчет в последнем улове.
источник
Недавно я размышлял над тем же, и мой предварительный вывод заключается в том, что простой вопрос возникает из-за того, что иерархия исключений .NET серьезно испорчена.
Возьмем, к примеру, простой,
ArgumentNullException
который может быть разумным кандидатом на исключение, которое вы не хотите перехватывать, потому что оно имеет тенденцию указывать на ошибку в коде, а не на допустимую ошибку времени выполнения. О да. То же самоеNullReferenceException
, за исключением того, чтоNullReferenceException
оно полученоSystemException
напрямую, поэтому нет корзины, в которую вы можете поместить все «логические ошибки», чтобы поймать (или не поймать).Кроме того, в IMNSHO есть главный недостаток -Когда вы получаетеSEHException
получить (черезExternalException
)SystemException
и, таким образом, сделать его «нормальным».SystemException
SEHException
, вы хотите написать дамп и завершить работу так быстро, как можете - и начиная с .NET 4, по крайней мере, некоторые Исключения SEH считаются поврежденными состояниями , которые не будут обнаружены. Хорошая вещь, и факт, который делаетCA1031
правило еще более бесполезным, потому что теперь ваш ленивыйcatch (Exception)
не поймает эти худшие типы в любом случае.Затем кажется, что другие компоненты Framework довольно непоследовательно извлекаются либо
Exception
напрямую, либо черезSystemException
, пытаясь сгруппировать предложения catch по какому-либо вопросу, связанному с серьезностью.Мистер Липперт
C#
, известный как Vexing Exception , предлагает вам полезную классификацию исключений: можно утверждать, что вы хотите поймать только «экзогенные» исключения, кроме ...C#
языка и дизайна .NET рамочные исключения делают невозможным «ловить только экзогенных» любым лаконичным образом. (и, например,OutOfMemoryException
может очень хорошо быть совершенно нормально неустранимая ошибка для API , который должен выделять буферы, которые как - то большой)Суть в том, что то, как
C#
работают блоки catch и как устроена иерархия исключений Framework, правилоCA1031
выходит за рамки абсолютно бесполезного . Он притворяется, что помогает с основной проблемой «не глотать исключения», но проглатывание исключений не имеет ничего общего с тем, что вы ловите, а с тем, что вы затем делаете:Есть как минимум 4 способа законно обработать пойманное
Exception
, иCA1031
только кажется, что поверхностно обрабатывает один из них (а именно случай повторного броска).Как примечание, есть функция C # 6 под названием « Фильтры исключений», которая снова станет
CA1031
немного более корректной, поскольку тогда вы сможете правильно, правильно, правильно фильтровать исключения, которые вы хотите перехватить, и меньше причин писать нефильтрованныеcatch (Exception)
.источник
OutOfMemoryException
заключается в том, что нет хорошего способа, которым код может быть уверен, что он «только» указывает на сбой определенного распределения, которое было подготовлено к сбою. Вполне возможно, чтоOutOfMemoryException
возникло еще одно более серьезное исключение, и во время разматывания стека произошло другое исключение. Java, возможно, опоздала на вечеринку со своими «try-with-resources», но она обрабатывает исключения во время разматывания стека немного лучше, чем .NET.finally
блоки от исключений, которые можно реально ожидать, чтобы они происходили таким образом, что оба исходных и новых исключения регистрируются. К сожалению, для этого часто требуется выделение памяти, что может вызвать собственные сбои.Обработка исключений Pokemon (должен поймать их всех!), Конечно, не всегда плохо. Когда вы предоставляете метод клиенту, особенно конечному пользователю, часто лучше поймать что-нибудь и все, чем иметь аварийное завершение работы приложения.
Как правило, хотя их следует избегать, где вы можете. Если вы не можете предпринять конкретные действия, основанные на типе исключения, лучше не обрабатывать его и не допустить, чтобы исключение всплыло, а затем проглотило исключение или обработало его неправильно.
Посмотрите на этот так ответ для большего количества чтения.
источник
LoadDocument()
, по сути, невозможно идентифицировать все вещи, которые могут пойти не так, но 99% исключений, которые могут быть сгенерированы, будут просто означать «Не удалось интерпретировать содержимое файла с данным именем как документ; разберись с ним ". Если кто-то пытается открыть что-то, что не является допустимым файлом документа, это не должно привести к сбою приложения и уничтожению любых других открытых документов. Обработка ошибок покемонов в таких случаях безобразна, но я не знаю хороших альтернатив.Поймать общее исключение плохо, потому что оно оставляет вашу программу в неопределенном состоянии. Вы не знаете, где что-то пошло не так, поэтому вы не знаете, что ваша программа на самом деле сделала или не сделала.
Я бы позволил поймать все при закрытии программы. Пока вы можете очистить его в порядке. Ничто так не раздражает, как закрываемая программа, которая просто выдает диалоговое окно с сообщением об ошибке, которое ничего не делает, кроме как сидит, не уходя и не мешая закрытию компьютера.
В распределенной среде ваш метод журнала может иметь неприятные последствия: перехват общего исключения может означать, что ваша программа по-прежнему удерживает блокировку файла журнала, не позволяя другим пользователям создавать журналы.
источник
Как уже говорили другие, действительно трудно (если не невозможно) представить какое-либо действие, которое вы хотели бы предпринять независимо от выданного исключения. Лишь одним примером являются ситуации, когда состояние программы было повреждено и любая дальнейшая обработка может привести к проблемам (это обоснование позади
Environment.FailFast
).Для хобби-кода это просто замечательно
Exception
, но для кода профессионального уровня введение нового типа исключения следует рассматривать с тем же уважением, что и изменение сигнатуры метода, то есть считаться критическим изменением. Если вы подпишетесь на эту точку зрения, то сразу станет очевидно, что возвращение к изменению (или проверке) клиентского кода - единственный правильный путь действий.Конечно, потому что вы не будете ловить только исключения
Bar
. Также будут исключения, которые клиенты Bar или даже среда выполнения могут выдавать в течение времени, котороеBar
находится в стеке вызовов. Хорошо написанныйBar
должен определять свой собственный тип исключения, если это необходимо, чтобы вызывающие могли специально перехватывать исключения, выдаваемые самим собой.ИМХО, это неправильный способ думать об обработке исключений. Вы должны работать с белыми списками (перехватывать типы исключений A и B), а не с черными списками (перехватывать все исключения, кроме X).
источник
Может быть . Есть исключения из каждого правила, и ни одно правило не должно соблюдаться некритически. Ваш пример, возможно, может быть одним из случаев, когда имеет смысл проглотить все исключения. Например, если вы хотите добавить трассировку в критическую производственную систему, и вы хотите быть абсолютно уверены, что ваши изменения не нарушают основную задачу приложения.
Однако вам следует тщательно обдумать возможные причины неудачи, прежде чем вы решите молча игнорировать их все. Например, что если причиной исключения является:
Разве вы не хотите, чтобы вас немедленно уведомили о наличии этой проблемы, чтобы вы могли ее исправить? Принятие исключения означает, что вы никогда не узнаете, что что-то пошло не так.
Некоторые проблемы (например, переполнение диска) могут также привести к сбою других частей приложения - но этот сбой не регистрируется сейчас, так что вы никогда не узнаете!
источник
Я хотел бы рассмотреть это с логической точки зрения, а не с технической точки зрения,
Ну, кто-то должен был бы справиться с этим. Это идея. Авторы библиотечного кода будут осторожны с добавлением новых типов исключений, хотя, поскольку это может привести к поломке клиентов, вы не должны сталкиваться с этим очень часто.
По сути, ваш вопрос: «Что, если мне все равно, что пошло не так? Мне действительно нужно пройти через испытание, чтобы выяснить, что это было?»
Вот часть красоты: нет, ты не.
«Итак, можно я просто посмотрю в другую сторону и сделаю так, чтобы всякая неприятная вещь всплыла под ковром автоматически и с этим покончено?»
Нет, это тоже не так.
Дело в том, что коллекция возможных исключений всегда больше, чем вы ожидаете, и заинтересованы в контексте вашей локальной маленькой проблемы. Вы справляетесь с теми, кого ожидаете, и если происходит что-то неожиданное, вы оставляете это обработчикам более высокого уровня, а не глотаете это. Если вас не волнует исключение, которого вы не ожидали, вы ставите кого-то в стек вызовов, и было бы саботажом убить исключение до того, как оно достигнет своего обработчика.
«Но ... но ... тогда одно из тех других исключений, которые меня не волнуют, может привести к сбою моей задачи!»
Да. Но они всегда будут важнее, чем локальные. Например, пожарная сигнализация или босс, говорящий вам прекратить то, что вы делаете, и поднять более неотложное задание, которое появилось.
источник
Вы должны отлавливать общие исключения на верхнем уровне каждого процесса и обрабатывать их, сообщая как можно скорее об ошибке, а затем завершая процесс.
Вы не должны отлавливать общие исключения и пытаться продолжить выполнение.
источник