Как лучше всего использовать try catch для обработки исключений

201

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

try
{
  //do something
}
catch
{
  //Do nothing
}

или иногда они записывают информацию журнала в файлы журнала, например, следующий try catchблок

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

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

Пожалуйста, дайте мне совет.

Тоан Нгуен
источник
128
Фрагмент № 1 в 99,999% случаев недопустим.
Леппи
22
Отображение исключения непосредственно пользователю никогда не является хорошей идеей, в основном по двум причинам: 1. если это обычный пользователь (пользователи), он будет раздражен чтением сообщения об ошибке, которое говорит ему очень мало. 2. если он, так называемый, хакер, он может получить полезную информацию. Рекомендуется регистрировать исключения и показывать понятное сообщение об ошибке.
Лери
4
@leppie Если происходит что-то непредвиденное (например, NullReferenceили ArgumentNullэто не является частью потока приложения), это означает, что есть ошибка, которую необходимо исправить, поэтому регистрация их поможет намного быстрее отладить ваш код.
Лери
14
Использование блока try-catch для скрытия исключения обычно является результатом ленивого программирования. Это ярлык, который часто используется вместо написания кода проверки для проверки входных данных. Очень редко бывают ситуации, когда может возникнуть исключение, которое не влияет на работу вашего кода, и скрыть его так можно. Это довольно редко, однако.
Кори
12
@ Тоан, ну, если это пакетное задание, я веду журнал на верхнем уровне (Main), чтобы записать его в журнал, а затем снова выбрасываю, чтобы вызвать сигнал тревоги о том, что задание прервано ненормально. Если это веб-приложение, я даю пузырю исключения исключение глобальному обработчику, веду журнал, а затем перенаправляю пользователя на экран ошибок. Ваш сценарий использования диктует, что вы будете делать с этим исключением после того, как вы вошли в систему или обработали ее иным образом.
Энтони Пеграм

Ответы:

300

Моя стратегия обработки исключений:

  • Чтобы поймать все необработанные исключения , подключив кApplication.ThreadException event , решите:

    • Для приложения с пользовательским интерфейсом: выложить его пользователю с сообщением извинения (winforms)
    • Для Сервиса или Консольного приложения: зарегистрируйте его в файл (сервис или консоль)

Тогда я всегда прилагаю каждый кусок кода , который выполняется снаружи в try/catch:

  • Все события, запускаемые инфраструктурой Winforms (Load, Click, SelectedChanged ...)
  • Все события запускаются сторонними компонентами

Тогда я прилагаю в «попробовать / поймать»

  • Все известные мне операции могут работать не всегда (операции ввода-вывода, вычисления с потенциальным делением на ноль ...). В таком случае я выкидываю новый, ApplicationException("custom message", innerException)чтобы следить за тем, что на самом деле произошло

Кроме того, я стараюсь правильно сортировать исключения . Есть исключения, которые:

  • должны быть показаны пользователю немедленно
  • требуется некоторая дополнительная обработка, чтобы собрать вещи вместе, когда они случаются, чтобы избежать каскадных проблем (например: поместить .EndUpdate в finallyраздел во время TreeViewзаполнения)
  • пользователю все равно, но важно знать, что произошло. Поэтому я всегда их регистрирую:

    • В журнале событий
    • или в файле .log на диске

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

Я также заставляю себя попытаться:

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

Итак, наконец:

Плохой:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

Бесполезный:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

Попытка, наконец, без улова совершенно допустима:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

Что я делаю на высшем уровне:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

Что я делаю в некоторых называемых функциях:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

Есть много общего с обработкой исключений (Custom Exceptions), но этих правил, которые я стараюсь помнить, достаточно для простых приложений, которые я делаю.

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

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}
Larry
источник
98
catch(Exception ex) { throw ex; }в C # хуже, чем избыточный (независимо от того, какой тип исключения вы ловите). Для отбрасывания используйте throw;. В первом случае исключение будет выглядеть так, как будто оно возникло у вас, throw exтогда как во втором случае оно будет правильно исходить из исходного throwутверждения.
CVn
2
Почему вы перехватываете Application.ThreadExceptionсобытие и заключаете каждое исключение в catch(Exception ex) {ex.Log(ex);}. Я бы, вероятно, согласился с тем, что первое является отличной практикой, но второе добавляет риск дублирования ваших журналов ошибок и скрывает, что произошло исключение. Также throw exочень, очень плохо.
Кит
1
Я понял про catch (Exception ex) {throw ex; } быть бесполезным. Так что я полагаю, что «избыточный» не лучшее слово, чтобы заявить «Не делай этого». Вот почему я немного изменил пост, чтобы лучше утверждать, что следует избегать двух первых примеров try catch.
Ларри
3
Отличный и конструктивный ответ, больше всего мне понравилась фраза « Только воздух» :) И спасибо за Application.ThreadExceptionмероприятие, я не знал об этом, очень полезно.
Махди Тахсилдари
61

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

Есть 3 обстоятельства, при которых использование try-catchимеет смысл.

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

  2. Если вам нужно что-то сделать для исключения (например, войти в систему или откатить транзакцию), перезапустите исключение.

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

Предположим, вы подключаетесь к удаленному API, здесь вы знаете, что ожидаете определенных ошибок (и в этих обстоятельствах есть что-то, что нужно), так что это случай 1:

try 
{
    remoteApi.Connect()
}
catch(ApiConnectionSecurityException ex) 
{
    // User's security details have expired
    return false;
}

return true;

Обратите внимание, что другие исключения не обнаруживаются, так как они не ожидаются.

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

try
{
    DBConnection.Save();
}
catch
{
    // Roll back the DB changes so they aren't corrupted on ANY exception
    DBConnection.Rollback();

    // Re-throw the exception, it's critical that the user knows that it failed to save
    throw;
}

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

Наконец, у нас есть пользовательский интерфейс - здесь мы не хотим иметь полностью необработанные исключения, но мы не хотим их скрывать. Здесь у нас есть пример случая 3:

try
{
    // Do something
}
catch(Exception ex) 
{
    // Log exception for developers
    WriteException2LogFile(ex);

    // Display message to users
    DisplayWarningBox("An error has occurred, please contact support!");
}

Тем не менее, большинство API или интерфейсов пользовательского интерфейса имеют общие способы выполнения случая 3. Например, ASP.Net имеет желтый экран ошибок, который выводит подробности исключений, но его можно заменить на более общее сообщение в производственной среде. Следование этим рекомендациям является наилучшей практикой, потому что это экономит вам много кода, а также потому, что регистрация ошибок и их отображение должны быть решениями конфигурации, а не жестко заданными.

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

Даже случай 2 можно заменить лучшими шаблонами, например областями транзакций (using блоки, которые откатывают любую транзакцию, не зафиксированную во время блока), затрудняют для разработчиков ошибочную модель оптимальной практики.

Например, предположим, у вас есть крупномасштабное приложение ASP.Net. Регистрация ошибок может быть через ELMAH , отображение ошибок может быть информативным YSoD локально и хорошим локализованным сообщением в производстве. Все соединения с базой данных могут осуществляться через области транзакций и usingблоки. Вам не нужен ни одинtry-catch блок.

TL; DR: Лучшая практика - вообще не использовать try-catchблоки.

Кит
источник
4
@Jorj, вам следует прочитать весь пост, и, если вы все еще не согласны, возможно, было бы более конструктивным опровергнуть один из моих аргументов, а не просто заявить, что вам не нравится мой вывод. Почти всегда есть лучший шаблон, чем try-catch- он может (очень редко) быть полезным, и я не утверждаю, что вы никогда не должны его использовать, но в 99% случаев есть лучший способ.
Кит
Лучший ответ на данный момент - почти каждый тип разработки .net имеет своего рода HANDLER, который гораздо лучше подходит для работы с исключениями на глобальном уровне, что значительно облегчает их последовательную обработку, а также значительно упрощает простое использование. в разработке (зачем кому-то копать файл журнала для трассировки стека?) @Kieth, я бы привел ваш TLDR и добавил несколько примеров глобальных обработчиков (например, ThreadException, Application_Error и т. д.). Безусловно, вылавливайте ОСОБЫЕ ошибки, но сумасшедшим образом добавлять метод в try / catch / log
b_levitt
34

Исключением является ошибка блокировки .

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

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

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

Например, если вы знаете, что некоторые целочисленные данные могут иметь неправильный формат, используйте int.TryParseвместоint.Parse . Есть много случаев, когда вы можете сделать это вместо того, чтобы просто сказать «если это не удастся, просто выбросить исключение».

Бросать исключения стоит дорого.

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

  • ASP.NET: Global.asax Application_Error
  • Другие: событие AppDomain.FirstChanceException .

Моя позиция заключается в том, что локальные try / catches лучше подходят для обработки особых случаев, когда вы можете перевести исключение в другое или если вы хотите «отключить» его для очень, очень, очень, очень, очень особого случая (ошибка библиотеки выбрасывание несвязанного исключения, которое необходимо отключить, чтобы обойти всю ошибку).

Для остальных случаев:

  • Старайтесь избегать исключений.
  • Если это невозможно: обработчики исключений первого шанса.
  • Или используйте аспект PostSharp (AOP).

Отвечая на @thewhiteambit на некоторый комментарий ...

@ thewhiteambit сказал:

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

Прежде всего, как исключение не может быть даже ошибкой?

  • Нет подключения к базе данных => исключение.
  • Неверный формат строки для разбора на исключение типа =>
  • Попытка разобрать JSON, и хотя ввод не является JSON => исключением
  • Аргумент, в nullто время как объект ожидался => исключение
  • В некоторых библиотеках есть ошибка => выдает неожиданное исключение
  • Есть сокетное соединение, и оно отключается. Затем вы пытаетесь отправить сообщение => исключение
  • ...

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

Исключением является ошибка, потому что в конце дня это объект, который собирает диагностическую информацию - у него есть сообщение, и это происходит, когда что-то идет не так.

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

Кроме того, я предлагаю всем проверить парадигму быстрого отказа, опубликованную Мартином Фаулером (и написанную Джимом Шором) . Именно так я всегда понимал, как обрабатывать исключения, даже до того, как попал в этот документ некоторое время назад.

[...] считать их «Фатальными ошибками» - совершенно неверное понимание того, что такое исключения.

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

Больше ответов о проблемах @thewhiteambit

Например, в случае отсутствия соединения с базой данных программа может в исключительном случае продолжить запись в локальный файл и отправить изменения в базу данных, как только она снова станет доступной. Ваш недопустимый приведение типа String-to-Number можно попытаться снова проанализировать с языковым переводом в Exception, например, если вы попытаетесь выполнить разбор по умолчанию с английского языка на Parse ("1,5"), и вы попробуете его снова с немецким переводом, который полностью хорошо, потому что мы используем запятую вместо точки в качестве разделителя. Вы видите, что эти исключения не должны даже блокировать, им нужна только некоторая обработка исключений.

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

  2. Разборе вещь также ожидаемый случай ( не исключительный случай ). Если вы ожидаете этого, вы не используете исключения для управления потоком! , Вы получаете метаданные от пользователя, чтобы узнать, какова его / ее культура, и для этого вы используете средства форматирования! .NET также поддерживает эту и другие среды, и это исключение, поскольку следует избегать форматирования чисел, если вы ожидаете, что ваше приложение / служба будет зависеть от конкретной культуры .

Необработанное исключение обычно становится ошибкой, но само исключение не является codeproject.com/Articles/15921/Not-All-Exceptions-Are-Errors

Эта статья просто мнение или точка зрения автора.

Так как Википедия может быть просто мнением автора (ов) статьи, я бы не сказал, что это догма , но проверь, что в статье « Кодирование за исключением» говорится где-то в некотором абзаце:

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

Это также говорит где-то:

Неправильное использование исключения

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

Честно говоря, я считаю, что программное обеспечение не может быть разработано без серьезного рассмотрения вариантов использования. Если вы это знаете ...

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

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

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

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

Матиас Фидемрайзер
источник
6

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

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

Бездумное кодирование - ЕДИНСТВЕННЫЙ вид неправильного кодирования. Тот факт, что вы чувствуете, что есть что-то лучшее, что может быть сделано в этих ситуациях, показывает, что вы вкладываетесь в хорошее кодирование, но избегайте попыток запечатлеть какое-то общее правило в этих ситуациях и понимаете причину чего-то, что бросить в первую очередь, и что Вы можете сделать, чтобы оправиться от этого.

ChrisCW
источник
6

Я знаю, что это старый вопрос, но никто здесь не упомянул статью MSDN, и это был документ, который действительно прояснил это для меня, MSDN имеет очень хороший документ по этому вопросу, вы должны ловить исключения, когда выполняются следующие условия:

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

  • Вы можете создать и выдать новое, более конкретное исключение.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • Вы хотите частично обработать исключение, прежде чем передать его для дополнительной обработки. В следующем примере блок catch используется для добавления записи в журнал ошибок перед повторным вызовом исключения.
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

Я бы посоветовал прочитать весь раздел « Исключения и обработка исключений », а также рекомендации по исключениям .

Хамид Мосалла
источник
1

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

fhnaseer
источник
1

За исключением, я пробую следующее:

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

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

В коде что-то вроде этого:

try{
    //Some code here
}
catch(DivideByZeroException dz){
    AlerUserDivideByZerohappened();
}
catch(Exception e){
    treatGeneralException(e);
}
finally{
    //if a IO operation here i close the hanging handlers for example
}
Sorcerer86pt
источник
1
Деление на ноль исключений и тому подобное лучше 0решать, предварительно проверив числитель, а не a try-catch. И зачем ловить Exceptionздесь дженерик ? Вам лучше позволить ошибке всплыть, чем иметь дело с ней здесь во всех случаях, когда вы этого не ожидаете.
Кит
Прочитайте лучше то, что я написал о приведенном мной примере - обратите внимание на «не в аргументах». Конечно, любой калькулятор должен проверить приведенные аргументы. То, что я говорил, было о средних шагах. В этот момент проверка пользовательских аргументов уже произошла. Также в некоторых приложениях лучше избегать всплывающих исключений. Некоторые приложения должны обрабатывать исключения молча, в то время как другие должны рассматривать исключения как ошибки. Например, веб-сервер должен работать даже при возникновении исключений, когда медицинское программное обеспечение (например, рентгеновские аппараты) должно прерываться при возникновении исключений.
Sorcerer86pt
Приложения не должны когда - либо рассматривать исключения молча. Иногда у вас есть исключение, которое может обработать код, но такое использование должно быть как редким, так и специфичным для ожидаемого исключения. Ваш пример веб-сервера плохой - он должен иметь параметры конфигурации, которые позволят вам выбрать, как регистрируются ошибки и отображаются ли они с подробностями или просто страницей HTTP 500, но они никогда не должны молча игнорировать ошибки.
Кит
Я пытаюсь понять, что действительно мотивирует людей добавить еще один синоним слова «goto». Но что касается деления на ноль, это будет ОДИН тип исключения, который я вижу, который оправдывает улучшение языка. Зачем? Потому что вполне может быть так, что A) ноль является статистически бесконечно малым в вашем наборе данных, и B) использование (разрешение) исключения может быть гораздо более эффективным, поскольку деление является одним из способов проверки делителя нуля. Когда A и B имеют значение true, среднее выполнение вашей программы будет быстрее с использованием исключения, и оно может быть даже меньше.
Майк Лейтон
1

Второй подход хорош.

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

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

Я рекомендую вам пойти на второй подход для всего вашего приложения.

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

Оставить пустой блок улова - хуже. Если есть ошибка, лучший способ ее исправить:

  1. Войдите в файл \ база данных и т. Д.
  2. Попробуйте исправить это на лету (возможно, попробуйте альтернативный способ выполнения этой операции)
  3. Если мы не можем это исправить, уведомим пользователя об ошибке и, конечно, прервем операцию.
Stasel
источник
0

Для меня обработка исключений может рассматриваться как бизнес-правило. Очевидно, что первый подход неприемлем. Второй вариант лучше, и он может быть на 100% правильным, если контекст так говорит. Например, сейчас вы разрабатываете надстройку для Outlook. Если надстройка создает необработанное исключение, пользователь Outlook теперь может знать об этом, поскольку Outlook не будет самоуничтожаться из-за сбоя одного из плагинов. И вам трудно понять, что пошло не так. Поэтому второй подход в данном случае, на мой взгляд, является правильным. Помимо регистрации исключения, вы можете решить отобразить сообщение об ошибке для пользователя - я считаю это бизнес-правилом.

Тай Ань Дюк
источник
0

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

Но в реальной жизни у вас может быть несколько ситуаций, когда вы хотите скрыть это

  1. Вы полагаетесь на сторонний компонент и хотите продолжить программу в случае ошибки.
  2. У вас есть экономическое обоснование, которое необходимо продолжить в случае ошибки
Григорий Нозик
источник
6
Нет . Есть не бросать Exception. Когда-либо. Бросайте соответствующий подкласс Exceptionвсего, что вы хотите, но никогда, Exceptionпотому что это не дает абсолютно никакой смысловой информации. Я совершенно не вижу сценария, в котором есть смысл бросать, Exceptionно нет его подкласса.
CVn
0

catchБез каких - либо аргументов , просто едят исключение и бесполезно. Что если произойдет фатальная ошибка? Нет никакого способа узнать, что случилось, если вы используете catch без аргументов.

Оператор catch должен перехватывать более конкретные исключения, например, FileNotFoundExceptionа затем в самом конце вы должны перехватить, Exceptionкоторый перехватит любое другое исключение и зарегистрирует их.

Anirudha
источник
Почему генерал catch(Exception)в конце? Если вы этого не ожидаете, лучше всего передать его на следующий уровень.
Кит
1
@ Да, вы правы ... нет смысла ловить исключения, которые вы не ожидаете, но вы можете сделать общее исключение для целей регистрации ...
Anirudha
0

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

Мой путь таков:

  • Перехватывать непослушные исключения на уровне приложения (т. Е. В global.asax) для критических исключений (приложение не может быть полезным). Эти исключения я не ловлю на месте. Просто зарегистрируйте их на уровне приложения и позвольте системе выполнять свою работу.
  • Поймать "на месте" и показать некоторую полезную информацию для пользователя (введен неправильный номер, не может разобрать).
  • Поймайте на месте и ничего не делайте о незначительных проблемах, таких как «Я проверю наличие обновлений в фоновом режиме, но служба не работает».

Это определенно не должно быть лучшей практикой. ;-)

Fanda
источник
0

Я могу сказать вам кое-что:

Фрагмент # 1 недопустим, потому что он игнорирует исключение. (это глотает, как будто ничего не случилось).

Так что не добавляйте блок catch, который ничего не делает или просто отбрасывает.

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

Не используйте исключения для нормальной логики программы потока. Например:

например, подтверждение ввода. <- Это недопустимая исключительная ситуация, скорее вы должны написать метод, IsValid(myInput);чтобы проверить, действителен ли элемент ввода или нет.

Дизайн кода, чтобы избежать исключений. Например:

int Parse(string input);

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

bool TryParse(string input,out int result); <- этот метод возвращает логическое значение, указывающее, был ли анализ успешным.

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

Roxy'Pro
источник