Подтвердить что ты не робот

Можно ли глотать все исключения, кроме критических, в определенных сценариях?

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

Я приведу пример .NET/С#. Скажем, у меня есть файл, который я хочу скопировать, и все, что мне действительно волнует, - успешная операция копирования или нет. Если копирование завершилось неудачно, мне все равно, если конкретное исключение было FileNotFoundException или исключение исключения IOException "Недостаточно места на диске" или что-то еще... Мое приложение будет нормально двигаться в этом случае, поскольку эта операция не критична.

Итак, идея, как реализовать это:

try 
{
  // try 
  System.IO.File.Copy(strFile, strFile + ".new");
} 
catch (Exception ex) 
{
  // if critical exception then rethrow
  if (IsCritical(ex)) 
      throw;

  // else just log and swallow...
  Console.WriteLine("Failed to copy the file: " + ex.Message);
}

где IsCritical (Exception ex) - вспомогательный метод, определяемый как:

public static bool IsCritical(Exception ex) 
{
  if (ex is OutOfMemoryException) return true;
  if (ex is AppDomainUnloadedException) return true;
  if (ex is BadImageFormatException) return true;
  if (ex is CannotUnloadAppDomainException) return true;
  if (ex is ExecutionEngineException) return true;
  if (ex is InvalidProgramException) return true;
  if (ex is System.Threading.ThreadAbortException) 
      return true;
  return false;
}

Этот вопрос основан на следующей статье: Обработка исключений в С# с учетом правила "Не выгружайте исключения, которые не могут обрабатывать"

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

Итак, это хороший подход для данного сценария? Если нет, то почему и что лучше делать?

4b9b3361

Ответ 1

Причина, по которой обычно рекомендуется не проглатывать исключения, заключается в том, что она может скрыть ошибки. Например, вы делаете что-то другое, чем выполнение File.Copy: вы также выполняете строчную обработку (strFile + ".new"). Это не может быть выбрано (кроме OOM), но если вычисление было более сложным, , вы могли бы скрыть ошибку.

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

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

Ответ 2

Эта строка меня немного беспокоит...

Если копирование завершилось неудачно, мне все равно, было ли исключение FileNotFoundException или исключение исключения IOException "Недостаточно места на диске" или что-то еще

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

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

Ответ 3

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

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

С точки зрения отладки это не имеет большого значения, если у вас есть доступ к коду, поскольку вы можете включить разбивку на все распространенные исключения времени выполнения в Visual Studio. (Отладка → Исключения → Исключения для обычного языка Runtime → Установите флажок слева)

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

Ответ 4

Я думаю, что каждый ваш блок try должен иметь несколько исключений catch ers - и они должны перейти от более к менее конкретным.

Ответ 5

Вы можете добавить несколько операторов catch для одной и той же попытки:

try
{
 //code here
}
 catch (FileNotFoundException ex1) 
{
  //Do whatever you want
}
catch (IOException ex2)
{
  //Do whatever you want
}

Я предлагаю обработать исключение, которое вы не считаете критическим и для всех остальных сделать только один catch (Exception er){throw ;}

Также просто для этого двух особых исключений достаточно просто поймать IOException, потому что IOException является родительским классом FileNotFountException

Ответ 6

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

Ответ 7

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

Поэтому я бы, наверное, сделал что-то вроде:

  try 
    {
      System.IO.File.Copy(strFile, strFile + ".new");
     //MyLibrary throws exception clases I defined so I know what they are all about
      MyLibrary.SomeClass.DoSomething(strFile);
    }
    catch(ExceptionTypeIDefinedInMyLibraryWhichIKnowICanSafelyIgnore iex)
    {
      Console.WriteLine("Not to worry: "+ iex.Message);
    }
    catch (Exception ex) 
    {
      //This absolute is not something I can handle. Log it and throw.
      Log(ex); throw;
    }

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

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

Таким образом, вы не будете сожжены, когда новое добавление OhMyGodThereAreZombiesInTheServer добавится в BCL, вы никогда не знаете, это может произойти...

то есть

try 
{
  // try 
  System.IO.File.Copy(strFile, strFile + ".new");
} 
catch (Exception ex) 
{
  // if critical exception then rethrow
  if (ICanHandleThis(ex)) 
  {
   Console.WriteLine("Failed to copy the file: " + ex.Message);
  }
  else
  {
   //step aside and let Dr McNinja deal with it
   throw;
  }     
}

public static bool ICanHandleThis(Exception ex) 
{
 //I don't care about these exceptions, they aren't critical
 //to my application for some reason.
 return (ex is SomeTrivialExceptionTypeIDontCareAbout 
        || ex is SomeOtherIgnorableExceptionType);

}