Почему try-catch в main () плохой? - PullRequest
17 голосов
/ 18 мая 2009

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

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

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

Ответы [ 15 ]

28 голосов
/ 18 мая 2009

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

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

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

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

11 голосов
/ 18 мая 2009

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

7 голосов
/ 18 мая 2009

Я вообще не понимаю, как это плохо.

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

Может быть, кто-то еще может предоставить встречное представление.

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

  1. войти
  2. показать пользователю диалоговое окно с указанием ПОЧЕМУ приложение выходит (в виде обычного текста, а не трассировки стека)
  3. что-то еще, что имеет смысл в контексте вашего приложения.
5 голосов
/ 18 мая 2009

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

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

5 голосов
/ 18 мая 2009

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

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

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

5 голосов
/ 18 мая 2009

Я не думаю, что это плохая практика сама по себе. Я думаю, что плохая практика была бы, если бы это был ЕДИНСТВЕННЫЙ блок try / catch, который был у вас в приложении.

3 голосов
/ 18 мая 2009

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

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

1 голос
/ 18 мая 2009

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

Application.ThreadException += new ThreadExceptionEventHandler(YourExceptionHandlingMethod); 

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

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

1 голос
/ 18 мая 2009

Измените это на это, и это хорошо

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

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

1 голос
/ 18 мая 2009

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

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

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

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