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

Есть ли какая-либо техническая причина для написания блока catch, содержащего только оператор throw?

Отказ от ответственности: хорошо известно, что catch (ex) { throw ex; } - это плохая практика. Этот вопрос не.


Во время копирования через исходные источники Microsoft я заметил следующий шаблон в много методов:

try {
    ...
} catch {
    throw;
}

Нет регистрации, нет кода отладки — просто простой catch { throw; }.

Поскольку, очевидно, ребята из Microsoft должны быть достаточно опытными в использовании С#, что может быть для этого, а не просто удалять блок catch (и оператор try) вообще? Есть ли техническая причина для такого кодирования или это просто стилистический выбор?

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

4b9b3361

Ответ 1

Это влияет на запуск фильтров исключений.

Учитывая

void f() {
  using (var x = AcquireResource()) {
    x.DoSomething();
    x.DoSomethingElse();
  }
}

против

void f() {
  try {
    using (var x = AcquireResource()) {
      x.DoSomething();
      x.DoSomethingElse();
    }
  } catch {
    throw;
  }
}

с

void g() {
  try {
    f();
  } catch (Exception ex) when (h()) {
    // ...
  }
}

Первая версия f позволит вызвать фильтр h() до того, как x будет удален. Вторая версия f гарантирует, что x будет удален до запуска внешнего кода.

В коде, к которому вы ссылаетесь, SqlConnectionHolder используется много, а catch { throw; } блоки вокруг использования SqlConnectionHolder.

Ответ 2

Как Спецификация С# описывает:

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

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

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

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

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

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

Ответ 3

Код, который вы связали, на самом деле является очень хорошим примером.

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

В коде, который вы связали, try catch находится вокруг материала базы данных.

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

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

Честно говоря, мне очень нравится то, что они там делали.