为什么main()中的try-catch不好?

有人可以向我解释为什么在main()方法中有一个try-catch来捕获任何未处理的exception是不合适的吗?

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

我知道这是不好的做法,但不确定原因。

我认为这不一定是不好的做法。 但是有一些警告……

我认为,任何称之为“不良做法”的人的观点都是强调你应该捕捉最接近它们发生位置的exception的想法(即尽可能高的调用堆栈/适当的)。 一揽子exception处理程序通常不是一个好主意,因为它大大减少了可用的控制流。 粗粒度exception处理非常重要, 不是程序稳定性的合理解决方案。 不幸的是,许多初学者开发人员认为它是,并采取这种方法,如这个毯子try-catch语句。

这样说, 如果你在程序的其余部分中正确使用了exception处理(以细粒度和任务特定的方式),并相应地处理了错误(而不是juist显示一般错误框), 那么一般尝试对Main方法中的所有exception进行捕获可能是一件有用的事情。 这里要注意的一点是,如果你可重复地捕获这个Main try-catch中的bug,那么你要么有一个bug,要么你的本地化exception处理有问题。

使用Main的这个try-catch的主要用途纯粹是为了防止你的程序在非常特殊的情况下崩溃,并且除了向用户显示(模糊地)用户友好的“致命错误”消息之外几乎不应该做任何事情。可能在某处记录错误和/或提交错误报告。 总而言之:这种方法确实有其用途,但必须非常谨慎地完成,而不是出于错误的原因。

好吧,这个方法只会捕获主线程中抛出的exception。 如果您同时使用Application.ThreadException和AppDomian.UnhandledException事件,那么您将能够捕获并记录所有exception。

我根本看不出那种糟糕的做法。

让程序因未处理的exception错误而崩溃,不会给最终用户增添任何信心。

也许其他人可以提供反制视图。

更新:显然你需要做一些有用的例外。

  1. 记录下来
  2. 向用户显示一个对话框,说明应用程序退出的原因(纯文本,而不是堆栈跟踪)
  3. 在您的应用程序的上下文中有意义的其他东西。

我不认为这本身就是一种不好的做法。 我认为不好的做法是,如果那是你应用程序中唯一的try / catch块。

在古代,在C ++中放置一个try / catch会导致相当沉重的性能损失,并且在main周围放置一个将意味着为所有内容存储额外的堆栈信息,这再次对性能不利。

现在计算机速度更快,程序员对性能的沉迷程度更低,而且运行时间更好,所以它不再那么糟糕(但是你可能会为它付出更多的代价,多年来没有对它的效果进行基准测试)。 所以这是一个古老的民间传说,就像反复对谷物一样(编译器现在无论如何都会为你修复迭代)。 在C#中它完全没问题,但是对于10年前的人来说它看起来很不错。

任何到达Main()exception都可能是致命的。

如果它很容易,它应该被处理得更高。 如果它是你无法控制的东西,比如OutOfMemoryException ,那么程序应该崩溃。

崩溃的Windows应用程序有一个标准的方法,它们会触发Windows错误报告对话框。 (你以前可能已经看过了)。 发生这种情况时,您可以注册接收崩溃数据。

我不确定我认为这是一种不好的做法。 你想要做的是确保程序崩溃时exception和程序的当前状态最终落在开发人员的手中,最好记录日期,时间和使用它的用户。 基本上 – 您希望确保您的团队拥有调试问题所需的所有信息,无论用户是否向他们了解崩溃。 请记住,如果发生崩溃,很多用户实际上都不会联系支持人员。

这里的不良做法是捕获exception,显示一个简单的“错误”对话框,并关闭应用程序。 在这种情况下,该exception的状态将永远丢失。

从调试的角度来看,这会使生活变得更加困难,因为它会使用户处理exception的每个exception。 这会更改调试器的行为,除非您中断未处理的exception,这可能还有其他问题。

话虽如此,我认为这在发布时是一个很好的做法。 另外,我建议也要监听AppDomain.UnhandledException和Application.ThreadException事件。 这将使您捕获更多exception(例如一些系统exception,这些exception将不会被上面的“全局”处理程序捕获)。

这允许您记录错误并为用户提供良好,干净的消息。

把它改成这个,没关系

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

当然,这行不应该被击中,因为你的代码中有其他exception处理程序可以捕获更多上下文。

顶级exception处理非常重要,但我建议使用:

 Application.ThreadException += new ThreadExceptionEventHandler(YourExceptionHandlingMethod); 

但是,这只会捕获GUI线程上的exception(很像你的try..catch块) – 你应该为每个新线程使用类似的代码来开始处理来自它们的任何意外exception。

更多关于它的信息 。

你有一个全能的例外,它会捕获所有东西。 因此,如果您的代码中有任何未处理的exception,您将永远不会看到它们。

从积极的方面来说,您的应用程序永远不会崩溃!

如果这是必需的行为,那么您需要有足够的日志记录和报告,让用户和您作为开发人员知道发生了什么,并尽可能优雅地恢复或退出。

我不是说这是不好的做法,我唯一能做的就是使用内置事件:

  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... } 

我认为这是不鼓励的,因为exception只被捕获一次,并且可能有多个事情,比如后台线程,需要知道进程是否抛出。

这是一个WinForms应用程序吗? 只要线程抛出未处理的exception, Forms.Application.Run引发事件。 MSDN文档尝试解释这一点,但他们显示的处理程序不起作用! 从WinForms UE站点读取更新的示例 。

如果你的程序试图继续运行,尽管抓住了 – 谁知道什么样的违反下面的假设,它就处于危险区域,例如远程利用安全漏洞(缓冲区溢出,堆损坏)。 将其置于循环中并继续运行是软件质量的一个重要标志。

尽快离开是最好的,例如退出(1)。 记录和退出虽然风险稍大但很好。

不相信我? 斜接普通弱点枚举(CWE)同意 。 密切相关的是它反对以这种方式捕获NULL指针解除引用的建议 。

我可以进行冗长的解释,但你最好只阅读FxCop团队的博客回复 。