赶上所有例外并做......没什么?

时间:2011-03-01 17:48:53

标签: c# exception-handling

我刚刚继承了超过300次出现的代码:

catch(Exception ex)
{
    string s = ex.Message ;
}

下次我遇到写这篇文章的人时,我该怎么办?

但是认真地......

这显然是编码恐怖,也是程序员可以做的最糟糕的事情之一。我是否应该通过并删除所有这些并查看运行应用程序时的真实情况?你怎么会纠正这个错误?

这是一个WinForms应用程序,在我的组织内部由大约24个用户运行。

10 个答案:

答案 0 :(得分:5)

每次出现异常时我都会先记录。然后看看其中有多少是重大问题。将它们全部关闭的问题现在你可能正在改变功能。功能损坏,但用户期望的功能。

答案 1 :(得分:5)

您可以在启动第一个表单之前删除所有这些catch块并添加以下代码:

public static void Main(string[] args)
{
// Event handler for handling UI thread exceptions.
Application.ThreadException += 
    new ThreadExceptionEventHandler(App_UiThreadException);

// Force all Windows Forms errors to go through our handler.
// NB In .NET 4, this doesn't apply when the process state is corrupted.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

// Event handler for handling non-UI thread exceptions. 
AppDomain.CurrentDomain.UnhandledException += new 
    UnhandledExceptionEventHandler(App_NonUiThreadException);

// Run the application.
}

拦截所有事件

调用SetUnhandledExceptionMode可确保无论应用程序配置设置如何都会拦截所有未处理的异常。

请注意,从.NET Framework 4开始,上面编写并在下面讨论的事件不会针对损坏进程状态的异常引发,例如堆栈溢出或访问冲突 - 除非事件处理程序是安全关键的并且具有HandleProcessCorruptedStateExceptionsAttribute属性。

exceptions that corrupt process state上有一篇有趣的博客文章。

UI线程例外

处理Application.ThreadException事件会拦截ui线程上未处理的异常。在您的过滤器代码中,您可以记录每个异常。如果要复制ui线程异常的现有行为,您应该能够吞下大部分内容。

非UI线程异常

处理AppDomain.UnhandledException事件会拦截非ui线程上的未处理异常。在您的过滤器代码中,您可以记录每个异常。不幸的是,大多数非ui线程异常在触发此事件时已经是致命的,因此不可能通过执行此操作来复制非ui线程异常的现有行为。

答案 2 :(得分:3)

引入日志记录机制并至少记录这些错误消息!

答案 3 :(得分:3)

我怀疑是原作者介绍了这些语句以方便调试。由于程序中的错误,代码很可能会抛出异常,原作者试图通过在不同的点捕获它来追踪它。

为什么这种神秘的方法?

  1. 作者不知道您可以将调试器配置为在抛出异常时中断( CTRL + ALT + E 在Visual Studio中)
  2. 如果在空的catch处理程序中调试并捕获异常,则很难跳到允许您访问处理程序范围和异常消息的语句(您需要知道将断点置于关闭状态撑)
  3. 如果没有no-op异常处理程序,应用程序运行良好,我不会感到惊讶;我会删除它们并添加一个顶级日志记录机制来记录其他人建议的未处理的异常。如果您通过日志发现可以处理未处理的异常,那么您将拥有其调用堆栈并知道在何处引入适当的处理程序。

答案 4 :(得分:2)

我会添加日志记录以在生产中评估它,并在dev中重新计算 - 以了解问题:

LogCrazyException(ex);
#if DEBUG
    throw;
#endif

答案 5 :(得分:2)

您可以简单地重新抛出异常,这样就可以在对代码进行最小更改的同时删除异常吞咽功能:

catch(Exception ex) {
  throw;
}

如果你只是删除所有try ... catch块,你可以在为每个try ... catch中的所有代码移除一个范围块时遇到范围问题。通过重新抛出它们,您可以看到错误经常发生的位置,以便您可以修复它们。然后,您可以在需要时添加适当的异常处理和/或日志记录,并删除它们无用的try ... catch块。

答案 6 :(得分:1)

除了那些位于事件处理程序顶层的人之外,我会将它们全部删除。在那个级别,我将显示一个包含异常信息的MessageBox。

答案 7 :(得分:0)

嗯..也许作家实际上并不想在出错的情况下什么也不做,因为没有抓住他就不可能尝试,只是为了让编译器开心。老实说,这看起来很奇怪,但如果程序有效......

答案 8 :(得分:0)

在某些情况下,捕获异常并且什么都不做是合适的。例如,当调用Control.BeginInvoke请求进度条控件自行更新时,如果某个其他线程可以处置该控件,则存在不可避免的(*)竞争条件。虽然一个人应该只能看到人们期望BeginInvoke抛出的异常,但是有一个哲学论证可以说任何会导致BeginInvoke抛出的条件都可能对UI线程感兴趣,但对工人来说并不是真正感兴趣的。试图提供礼貌更新通知的线程。 BeginInvoke中系统将被捕获的任何异常都不应该影响工作线程,并且不会捕获那些无法捕获的线程。没有任何理由可以解释为什么UI相关异常应该从一个例程中逃脱,该例程的目的不是更新UI,而是应该执行业务逻辑(将进度条更新视为礼貌的副作用)。

所有这一切,对于Try-Catch-Ignore模式来说,300次听起来太多了。如果有很多例如包含在这些catch块中的BeginInvoke语句应该被拉出到其他一些TryBeginInvoke例程中。同样,如果有许多其他函数调用返回不能做任何事情的异常。虽然我可以想象可能会有300个函数调用一些函数来回复这些令人烦恼的异常,但我怀疑有300个这样的函数。

(*)可以使用锁来保护BeginInvoke和Dispose方法,但这会增加相当大的复杂性并为出错的地方创造更多机会。如果存在.net TryBeginInvoke方法,那将是美丽的。由于它不存在,编写这样的例程以使用Try-Catch-Ignore块包装BeginInvoke似乎是最好的方法。

答案 9 :(得分:0)

try{

}
catch (Exception)
{
}

会阻止出现警告信息