Какие исключения я не должен ловить? - PullRequest
16 голосов
/ 22 августа 2011

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

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

Итак, мой вопрос: есть ли достаточно короткий список критических исключений, которые я могу перебросить в своем нижнем обработчике исключений, подавляя (после регистрации) все остальное?

Спасибо!

Редактировать: Для уточнения, вот основная структура моей программы

foreach(var item in longItemList)
{
   try
   {
      bigDynamicDispatchMethod(item);
   }
   catch(Exception ex)
   {
      logException(ex);
   }
}

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

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

Есть ли лучший способ структурировать мое приложение, чтобы справиться с этим? Я открыт для предложений.

Ответы [ 6 ]

25 голосов
/ 22 августа 2011

Вам не нужен список «плохих» исключений, по умолчанию вы должны рассматривать все как плохие. Только поймать то, что вы можете справиться и восстановить. CLR может уведомлять вас о необработанных исключениях, чтобы вы могли соответствующим образом регистрировать их. Проглатывание всего, кроме перечисленных в черном списке исключений, не является правильным способом исправить ваши ошибки. Это бы просто замаскировало их. Прочитайте это и это .

Не исключать каких-либо особых исключений при ловле с целью передачи исключений.

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

public class BadExceptionHandlingExample2 {
    public void DoWork() {
        // Do some work that might throw exceptions.
    }
    public void MethodWithBadHandler() {
        try {
            DoWork();
        } catch (Exception e) {
            if (e is StackOverflowException ||
                e is OutOfMemoryException)
                throw;
            // Handle the exception and
            // continue executing.
        }
    }
}

Несколько других правил:

Избегайте обработки ошибок, перехватывая неконкретные исключения, такие как System.Exception, System.SystemException и т. Д. В приложении код. Есть случаи, когда обработка ошибок в приложениях приемлемо, но такие случаи редки.

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

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

Вы должны ловить только те исключения, которые вы можете восстановить. За Например, FileNotFoundException, возникающая в результате попытки открыть несуществующий файл может быть обработан приложением, потому что он может сообщить о проблеме пользователю и позволить пользователю указать другое имя файла или создать файл. Запрос на открытие файла, который создает ExecutionEngineException не должны быть обработаны, потому что причина исключения не может быть известна с какой-либо степенью конечно, и приложение не может гарантировать, что это безопасно продолжить выполнение.

Эрик Липперт классифицирует все исключения на 4 группы: Fatal, 'Boneheaded', Vexing, Exogenous. Вот мое толкование совета Эрика:

  Exc. type | What to do                          | Example
------------|-------------------------------------|-------------------
Fatal       | nothing, let CLR handle it          | OutOfMemoryException
------------|-------------------------------------|-------------------
Boneheaded  | fix the bug that caused exception   | ArgumentNullException
------------|-------------------------------------|-------------------
Vexing      | fix the bug that caused exception   | FormatException from 
            | (by catching exception  because     | Guid constructor
            | the framework provides no other way | (fixed in .NET 4.0 
            | way of handling). Open MS Connect   | by Guid.TryParse)
            | issue.                              | 
------------|-------------------------------------|-------------------
Exogenous   | handle exception programmatically   | FileNotFoundException 

Это примерно эквивалентно классификации Microsoft : использование, программная ошибка и системный сбой. Вы также можете использовать инструменты статического анализа, такие как FxCop , чтобы обеспечить некоторые этих правил.

11 голосов
/ 22 августа 2011

Не отлавливайте никаких исключений, которые вы не знаете, как безопасно обрабатывать.

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

1 голос
/ 22 августа 2011

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

  • Чтение из MSDN Google исключения обработки лучшие практики
  • Никогда не замечайте неспецифических исключений, таких как Exception
1 голос
/ 22 августа 2011

Я бы сослался на совет из следующей статьи.

Правила руководящих принципов проектирования .NET Framework: не перехватывать исключения, которые вы не можете обработать

http://www.codeproject.com/KB/cs/csmverrorhandling.aspx

Также из упомянутой статьи:

Вы никогда не должны перехватывать System.Exception или System.SystemException в блоке перехвата

1 голос
/ 22 августа 2011

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

1 голос
/ 22 августа 2011

Более правильный дизайн будет поддерживаться вопросом: Какие исключения должен Я поймаю?

Если вам действительно нужно перехватить все без исключения исключения и продолжать работу, тогда вам следует использовать как AppDomain, так и отдельные рабочие процессы. Или измените свой хост на ASP.NET или планировщик задач, которые уже выполнили всю тяжелую работу по изоляции процессов и повторных попыток.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...