Единая обработка многих исключений - PullRequest
4 голосов
/ 14 декабря 2011

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

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

То, что у меня сейчас есть, примерно так в каждом методе моей библиотеки:

try
{
   // some code
}
catch (Exception1 e)
{
}
catch (Exception2 e2)
{
}
  ...
catch (ExceptionN eN)
{
}

Количество исключений также может увеличиться.

Как я могу уменьшить дублирование кода и единообразно обработать все исключения в одном месте?

  • предположим, что обработка в каждом методе в моем коде одинакова.

Ответы [ 5 ]

5 голосов
/ 14 декабря 2011

Я бы начал с перехвата базового типа Exception и последующей фильтрации по белому списку:

try
{
   // Code that might throw.
}
catch (Exception e)
{
    if(e is Exception1 || e is Exception2 || e is ExceptionN) 
    {
         // Common handling code here.
    }
    else throw; // Can't handle, rethrow.
}

Теперь, если вы хотите обобщить фильтр , вы можете написать расширение:

public static bool IsMyCustomException(this Exception e)
{
    return e is Exception1 || e is Exception2 || e is ExceptionN;
}

и тогда вы можете просто использовать:

if(e.IsMyCustomException())
{
    // Common handling code here.
}
else throw;

Вы можете обобщить обработчик с помощью простого метода:

private void HandleCustomException(Exception e)
{
    // Common handling code here.
}

Если вы хотите обобщить весь блок try-catch, вам, вероятно, лучше всего внедрить делегат в метод, который упаковывает операцию, как упомянуто в @vc 74.

3 голосов
/ 14 декабря 2011

Вы можете использовать глобальный обработчик исключений, реализация зависит от типа вашего проекта (ASP.net -> global.asax, WPF -> App.xaml ...)

Или используйте что-то вроде следующего:

private static void HandleExceptions(Action action)
{
    try
    {
       action();
    }
    catch (Exception1 e)
    {
    }
    catch (Exception2 e2)
    {
    }
      ...
    catch (ExceptionN eN)
    {
    }
}

, который может быть вызван следующим образом:

HandleExceptions(() => Console.WriteLine("Hi there!"));

Если во время выполнения Console.WriteLine возникло исключение, оно будет обработано вашей логикой обработки исключений

Обратите внимание, что код для выполнения может также изменять внешние значения:

int x = 2;
HandleExceptions(() => x = 2 * x);

Если вы предпочитаете анонимные методы:

var x = 2;
HandleExceptions(delegate()
{
  x = x * 2;
});
1 голос
/ 14 декабря 2011

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

Вы можете прочитать все об этом здесь ...

1 голос
/ 14 декабря 2011

как насчет использования одной функции для обработки этих исключений:

try
{
  //Some code here
}
catch(Exception e)
{
  if(!ErrorHandler(e))
      return null; //unhandled situation
}

private bool ErrorHandler(Exception e)
{
 switch(e)
 {
     case Exception1:
     //Handle the exception type here
     return true;
     case Exception2:
     //Handle another exception type here
     return true;
 }
 return false;
}
0 голосов
/ 14 декабря 2011

Существуют некоторые семантические различия между перехватом и повторным созданием исключения, а не его перехватом. Фильтры исключений поэтому очень полезны, так как они позволяют, например, Msgstr "Поймать Ex как исключение, когда IsNiceException (Ex)". К сожалению, единственный способ использовать их в программе на C # - это использовать DLL, чтобы обернуть необходимую функциональность (сама DLL может быть написана на vb или другом языке). Типичный шаблон может быть что-то вроде:

  TryWhenCatchFinally( 
    () => {trycode;},
    (Exception ex) => {codeWhichReturnsTrueForExceptionsWorthCatching;},
    (Exception ex) => {codeToHandleException;},
    (ExceptionStatus status, Exception ex) => {finallyCode;});

Параметр ExceptionStatus для кода "finally" будет перечислением, указывающим, было ли (1) исключение не произошло, (2) исключение произошло, но было обработано, (3) произошло исключение и было обработано, но другое исключение было выдается или (4) возникла исключительная ситуация, но CodeWhichReturnsTrueForExceptionsWorthCatching вернул false; (5) возникла исключительная ситуация, которая не была обработана в trycode и не обработана этим блоком, но trycode завершился в любом случае (редкая ситуация, но есть способы, которыми это может произойти). Параметр Ex будет нулевым в первом случае и будет содержать соответствующее исключение в других - потенциально полезную информацию, которая будет иметься, если во время обработки блока finally возникает исключение (подавление исключения, возникающего в блоке finally, может быть плохим, но если более раннее исключение не регистрируется или теряется до того, как новое исключение исчезнет, ​​все данные из более раннего исключения, как правило, будут потеряны: если то же условие, которое вызвало более раннее исключение, вызвало более позднее, более раннее исключение может иметь более полезную информацию о том, что произошло неправильно).

Кстати, несколько заметок с этим шаблоном:

  1. Код, который решает, поймать ли исключение, будет запущен до выполнения вложенных блоков finally; он может собирать полезные данные для регистрации (тот факт, что блоки finally не запускаются, может сделать доступной для регистрации информацию, которая может быть уничтожена вложенными блоками finally), но фактическая очистка обычно должна выполняться после запуска блоков finally.
  2. В настоящее время кажется, что исключения, которые могли бы выйти из фильтров, были подавлены, но я не уверен, что поведение гарантировано. Операции, которые могут привести к утечке исключений, вероятно, не должны выполняться внутри фильтров.
  3. Если «trycode» содержит блок try-finally, который вложен в блок try-catch, исключение, которое возникает в части «try» этого блока try-finally, не обрабатывается TryCatchWhenFamily и не является вложенной областью действия, но обрабатывается внешним блоком, и обработка внутреннего блока try-finally вызывает исключение, которое обрабатывает внутренний блок try-catch, исключение, которое, как решил внешний блок, он собирался перехватить, может исчезнуть без возможности быть пойманным. Если метод TryWhenCatchFinally закодирован для обнаружения этого условия, он может сообщить об этом своему блоку кода finally (блок finally может или не может захотеть что-либо сделать с этим условием, но, вероятно, его следует как минимум зарегистрировать).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...