Какова должна быть лучшая Стратегия Обработки исключений

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

UI-> Method1-> Method2-> Method3

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

Я пойду с выдачей исключения непосредственно к методу вызывающей стороны, и на уровне UI я поймаю исключение и отображу сообщение.

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

Я не хочу использовать конвенцию C++, куда целое число возвращается как результат.

10
задан Ram 7 July 2010 в 10:09
поделиться

7 ответов

Учитывая ваш пример UI--> Method1 -->Method2 --> Method3, я бы убедился, что пользовательский интерфейс имеет try/catch, но тогда ни один из других методов не должен перехватывать исключения, если они не могут обрабатывать их без повторного броска. И даже если они обрабатывают исключение, вы должны задаться вопросом, должно ли это исключение произойти в первую очередь. Если вы обрабатываете исключение и идете своим веселым путем, то это исключение является частью вашего нормального процесса, который является серьезным запахом кода.

Вот мои рекомендации:

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

protected void Button1_Click(object sender, EventArgs e) {
   try {
      DoSomething();
   }
   catch Exception e {
      HandleError(e);
   }
}

2) Не делайте этого. Вы потеряете трассировку стека, и следующий разработчик, который будет поддерживать ваш код, будет выслеживать вас.

try {
   DoSomething();
}
catch Exception e {
   throw e; // don't rethrow!!!
}

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

try {
   DoSomething();
}
catch SomeException e {
   HandleException(e);
}
catch {
   throw ; // keep my stack trace.
}

3) Выбрасывайте исключения только в исключительных обстоятельствах. Не идьте блоки try/catch как часть вашего обычного технологического процесса.

4) Если вы собираетесь создать исключение, не выбрасывайте ever System.Exception. Наследуйте объект исключения и выбрасывайте его. Я часто просто общий BusinessException класс. Таким образом, пользователи вашего кода могут определить, какие исключения вы создали, а какие связаны с системой или средой.

5) Бросок ArgumentException, ArgumentNullException или ArgumentOutOfRangeException, если вызывающий метод нарушает контракт (предварительные условия) вашего метода. Если вы поймаете один из них, это ошибка программирования. Пользователь никогда не должен видеть эти исключения.

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

3
ответ дан 3 December 2019 в 15:34
поделиться

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

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

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

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

Если вы хотите улучшить сообщение об ошибке, вы поймаете, перенесете новое исключение и выбросите. Например, вы можете захотеть заключить универсальное исключение FileNotFoundException при чтении файла в новое исключение с более описательным сообщением, сообщающим пользователю, какой файл не может быть найден.

2
ответ дан 3 December 2019 в 15:34
поделиться

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

public enum AddCustomerResult
{
    Success,
    CustomerAlreadyExists,
    CustomerPreviouslyRetired
}

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

Это лишь одна из техник, которая хорошо работает для меня.

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

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

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

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

Надеюсь, это поможет!

1
ответ дан 3 December 2019 в 15:34
поделиться

Что бы вы ни решили - будьте последовательны . Через 30 дней вы (или другой разработчик) должны будете понять свой код.

Кроме того, как Скотт Хансельман любит цитировать в своем подкасте (и я думаю, что это может быть в книге Beautiful Code) -

Все проблемы в информатике могут быть решены с помощью другого уровня косвенного обращения. , "- известная цитата, приписываемая Батлеру Лэмпсону, ученому, который в 1972 году придумал современный персональный компьютер.

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

public class MyException : Exception
{
   private MyException(Exception ex, string msg) {
       this.Message = msg;
       this.InnerException = ex;
   }

   internal static MyException GetSomethingBadHappened(Exception ex, string someInfo) {
      return new MyException(ex, someInfo);
   }
}
2
ответ дан 3 December 2019 в 15:34
поделиться

Почти всегда стоит разделять обработку исключений и отчет об ошибках.

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

После завершения операции или шага уровень пользовательского интерфейса может проверить журнал ошибок и выдать сообщение "Произошли следующие ошибки: ...".

0
ответ дан 3 December 2019 в 15:34
поделиться

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

1
ответ дан 3 December 2019 в 15:34
поделиться

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

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

19
ответ дан 3 December 2019 в 15:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: