Идея насчет синтаксиса обработки исключений

Written by elwood

Часто приходится писать обработчики исключений, которые делают одно и то же. Например, в следующем кусочке кода нам необходимо среагировать на исключения типа Exception1 и Exception2 записью в лог-файл :

try {
  // Блок, который может вызвать исключения Exception1, Exception2
  // или исключение любого другого типа
} catch (Exception1 exc) {
  logger.WarnException("An exception has been occured : {0}", exc);
} catch (Exception2 exc) {
  logger.WarnException("An exception has been occured : {0}", exc);
}

Проблема в том, что мы не можем никак избежать дублирования кода. Единственный выход – создать отдельный метод-обработчик, в котором и инкапсулировать логику. Но – во-первых, это может оказаться неудобным, поскольку локальные переменные, которые могут понадобиться в обработчике, придется передавать при вызове функции, а во-вторых, сам по себе вызов функции – это еще несколько тактов процессора.
Хотелось бы иметь способ, который бы позволял писать, скажем, следующим образом :

try {
  // 
} catch (Exception1, Exception2 exc as Exception) {
  // exc имеет тип Exception
}

(Предполагается, что типы Exception1 и Exception2 занаследованы от базового класса Exception).
Этот код мог бы преобразовываться в следующий :

 
Exception exc = null;
try {
  // 
} catch (Exception1 exc1) {
  exc = exc1;
  goto exception_real_handler;
} catch (Exception2 exc2) {
  exc = exc2;
  goto exception_real_handler;
}
 
exception_real_handler:
// Работаем с exc как с базовым типом Exception.

На мой взгляд, это было бы не сложно реализуемым дополнительным синтаксическим сахаром. Вполне применимо к c#, java и C++. Хотя, на счет последнего сомневаюсь, поскольку в С++ на поверку все оказывается несколько сложнее, чем изначально предполагаешь 🙂

Единственное – это необходимо продумать, каким образом компилятор должен реагировать на конструкции вида catch (Exception1, Exception2 exc as Exception) в случае, если Exception1 занаследован от Exception2. Мне видятся несколько путей, по которым мог бы пойти компилятор.

  • Выдавать ошибку при компиляции.
    Самый жесткий поход. На мой взгляд, это излишне.
  • Игнорировать наличие более конкретных типов.
    Т.е. если идет строчка catch (Exception1, Exception2 exc as Exception), в которой Exception1 : Exception2, то она будет интерпретирована как простой catch (Exception2). Вполне понятный подход.
  • Игнорировать и выдавать предупреждение – наверное, самый правильный способ.