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

Почему try-catch в main() плохой?

Может ли кто-нибудь объяснить мне, почему считается неприемлемым, чтобы попытаться использовать метод main() для обнаружения любых необработанных исключений?

[STAThread]
static void Main()
{
    try
    {
        Application.Run(new Form1());
    }
    catch (Exception e)
    {
         MessageBox.Show("General error: " + e.ToString());
    }
}

У меня есть понимание, что это плохая практика, но не знаю, почему.

4b9b3361

Ответ 1

Я не думаю, что это была плохая практика. Однако есть несколько предостережений...

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

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

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

Ответ 2

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

Ответ 3

Я не вижу, как эта плохая практика вообще.

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

Возможно, кто-то еще может предоставить счетчик.

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

  • зарегистрировать его
  • показать пользователю диалоговое окно, в котором указано, ПОЧЕМУ приложение выходит (в текстовом виде, а не в стеке)
  • что-то другое, что имеет смысл в контексте вашего приложения.

Ответ 4

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

Ответ 5

Любое исключение, попадающее в Main(), может быть фатальным.

Если бы это было что-то простое, его следовало бы обработать выше. Если это было что-то вне вашего контроля, например OutOfMemoryException, тогда программа должна потерпеть крах.

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

С положительной стороны ваше приложение никогда не сбой!

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

Ответ 9

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

Говоря, я считаю, что это хорошая практика во время релиза. Кроме того, я рекомендую прослушивать AppDomain.UnhandledException и Application.ThreadException, а также. Это позволит вам уловить еще больше исключений (например, некоторые системные исключения, которые не будут пойманы в вашем "глобальном" обработчике выше).

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

Ответ 10

Измените его на это, и оно прекрасное

catch(Exception ex)
{
    YourLoggingSystem.LogException(ex);
}

Конечно, эта строка НИКОГДА не должна быть удалена, так как у вас будут другие обработчики исключений во всех ваших кодах, захватывающие вещи с гораздо большим контекстом.

Ответ 11

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

Application.ThreadException += new ThreadExceptionEventHandler(YourExceptionHandlingMethod); 

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

Подробнее об этом здесь.

Ответ 12

Я не говорю, что это плохая практика, единственное, что я делал бы иначе, это использовать встроенное событие для этого:

        Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

        static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.Message); //or do whatever...
        }

Ответ 13

Я думаю, что лучше всего попробовать try..catch в вашем main().

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

[STAThread]
static void Main()
{
    try
    {
        Application.Run(new Form1());
    }
    catch (Exception ex)
    {
        EventLog log;
        log = new EventLog("MyApp", Environment.MachineName, "Application");

        // write to the event log
        log.WriteEntry(ex.message, Error);
        MessageBox.Show("General error");    
    }
}

Ответ 14

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

Это приложение WinForms? Forms.Application.Run вызывает события всякий раз, когда поток генерирует необработанное исключение. Документы MSDN пытаются объяснить это, но обработчик, который они показывают, не работает! Прочтите обновленный пример с сайта UF WinForms.

Ответ 15

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

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

Не верьте мне? Перечисление общего уровня слабости (CWE) согласуется с. Тесно связанный с этим совет против поиска NULL-указателя разыменования таким образом.