Обработка исключений в C #: несколько попыток / ловит против одного - PullRequest
5 голосов
/ 16 декабря 2008

Является ли хорошей практикой иметь более одного try{} catch{} оператора на метод?

Ответы [ 12 ]

14 голосов
/ 16 декабря 2008

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

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

6 голосов
/ 16 декабря 2008

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

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

6 голосов
/ 16 декабря 2008

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

try
{
    // a bunch of risky code
}
catch (SpecificException1 ex1)
{
     // handle Specific Exception 1
}
catch (SpecificException2 ex2)
{
     // handle Specific Exception 2
}
catch (SpecificException3 ex3)
{
     // handle Specific Exception 3
}
catch (Exception ex)
{
     // handle an exception that isn't specific
}
6 голосов
/ 16 декабря 2008

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

4 голосов
/ 18 декабря 2008

Для сложных сценариев производственного уровня ужасно иметь несколько операторов try-catch, и крайне негибко использовать эти операторы в бизнес-логике вообще.

Команда облачных вычислений Windows (их код должен быть эффективным и надежным), похоже, придерживается политики Исключительная обработка действий .

Этот код является лучшей заменой:

// perform action within the policy
policy.Do(() => repository.AddMessages(someMessages));

В то время как старые блоки кода выглядят так:

try
{
  repository.AddMessages(someMessages);
}
catch (Exception1 ex)
{
  // dosomething...
}
catch (Exception2 ex)
{
  // second handler
}
catch (Exception3 ex)
{
  // third handler
}

или (это способ предоставления настраиваемого обработчика исключений в корпоративной политике Microsoft Enterprise Library):

try
{
  repository.AddMessages(someMessages);
}
catch (Exception ex)
{
  bool rethrow = ExceptionPolicy
    .HandleException(ex, "Global Policy");
  if (rethrow)
  {
    throw;
  }
}

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

4 голосов
/ 16 декабря 2008

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

2 голосов
/ 16 декабря 2008

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

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

Не используйте одну попытку {} catch {}, чтобы обернуть весь контент вашего метода, таким образом снимая ответственность за достойные методы кодирования.

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

Принимайте осознанное решение, когда используете try / catch, не просто бросайте его, потому что можете, это лениво. Спросите себя: «Мне это нужно здесь?» Или «Могу ли я сделать это, используя менее дорогой и / или более структурированный подход?».

1 голос
/ 16 декабря 2008

Недопустимо даже иметь 1 попытку / улов на метод.

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

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

Итак ... совет: у вас должно быть наименьшее количество попыток / уловов, которое вы можете иметь, и это должно означать, что большинству методов не понадобится.

Но вот некоторые места, где их следует использовать:

  • В случае сбоя операции (для записи в файл журнала или для отображения пользователю сообщения об ошибке), Делайте это только в том случае, если вы знаете, что программа может продолжаться и не находится в поврежденном состоянии из-за сбоя одной операции. Операции должны быть изолированы друг от друга.
  • В вашем методе Main регистрируйте любые исключения, которые не были обработаны где-либо еще до того, как ваша программа прервалась из-за этого.
  • В местах, где вы можете предпринять какие-либо действия, такие как повторное выполнение операции или переход к более низкому режиму работы.
  • Там, где есть плохой API, который не позволяет вам проверять состояние, которое вам нужно обработать. Например, если вы хотите открыть файл, а API-интерфейс не предоставил DidFileExist (), вы можете сначала вызвать его.

Я не могу сейчас думать ни о чем другом ... это потому, что try / catch должно быть немного и далеко друг от друга!

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

1 голос
/ 16 декабря 2008

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

try
{
   Operation1();
}
catch (MySpecificException1)
{
   RecoverFromExpectedException1();
}
try
{
  Operation2();
}
catch (MySpecificException2)
{
   RecoverFromExpectedException2();
}

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

1 голос
/ 16 декабря 2008

Я обнаружил, что объединение многих строк кода, каждая из которых может выдать свое собственное исключение в один блок try со многими перехватчиками, затрудняет чтение кода. Из простого просмотра кода не очевидно, какая строка кода генерирует какое исключение. По моему мнению, try catch должен содержать как можно меньше кода; только код, который может выдать данное исключение. Если метод, который вы пишете, содержит несколько попыток перехвата, каждый из них должен быть извлечен в свои собственные методы.

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

Object operationResult;
try {
  operationResult = remoteService.performRemoteOperation();
} catch (RemoteException ex) {
  throw new BusinessException("An error occured when getting ...", ex);
}

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