全局try catch

11

我知道try catch已经被讨论了很多次,但我还没有找到解决我的问题的方法。

我正在编写一个Silverlight应用程序,每个异常都应该生成一个MessageBox,显示类似“对不起造成的不便”这样的消息。

由于我不能保证我的代码不会出现异常,我的同事指示我在每个方法中(有几百个)都要像这样使用try catch:

public void Method1()
{
    try
    {
        ...
    }
    catch (Exception e)
    {
        MessageBox.Show("Something went wrong, we apologize for the inconvenience. \n" + e.Message);
    }
}

public void Method2()
{
    try
    {
        ...
    }
    catch (Exception e)
    {
        MessageBox.Show("Something went wrong, we apologize for the inconvenience. \n" + e.Message);
    }
}

但这看起来过于繁琐。我读过不要以这种方式使用try catch,而且会有很多重复的代码,代码也会变得晦涩难懂。

是否有任何替代方案,例如我可以使用全局try catch吗?


7
你不想在每一个异常出现的地方都去捕获它。在调用栈高层可能有一些处理程序是有意义的(虽然错误信息没什么用)。但是没有充分理由而忽略异常是非常糟糕的想法。 - user395760
2
如果你不知道如何处理异常,为什么只显示一个消息框?你应该终止应用程序,因为它现在处于未知状态(假设这个异常是 OutOfMemoryException,你真的想尝试继续运行吗?)。 - Oded
3
@Oded 大多数异常都是非致命的,但很少有人知道如何在引发它的相同方法中处理它们。如果应用程序每次引发无法在同一位置处理的异常时都终止,我们甚至无法启动许多应用程序,更不用说对它们做错什么了。明智的做法是让异常上升到知道如何处理它的人,或者知道没有更高层的人知道它。 - user395760
@delnan 他没有说要在每个异常上终止程序。但是,原帖中的代码不应该捕获每个通用异常并仅显示一个消息框,有时会让用户面对一个崩溃或无响应的程序。 - jzworkman
1
@delnan - 我的观点是关于全局异常处理程序(顶级异常处理程序)试图进行“口袋妖怪式”的异常处理。 - Oded
3个回答

9

1
需要注意的是,为任何异常(特别是需要终止应用程序的异常)显示消息框仍然是一种不良实践。 - jzworkman
1
UI偏好设置,这可能不是最专业的做法,这是真的。 - Micah Armantrout
在任何异常情况下显示消息框是不好的做法吗?为什么? - Kiquenet
在用户环境中,用户不知道它的含义,这只会让他们更加困惑。 - Micah Armantrout

7
在每个单独的方法中添加try-catch是愚蠢的,但是:你的同事为什么要求你捕获异常到那种程度呢?难道你让异常滑过去,到了不想要的程度吗?
我曾经遇到过这样一个问题。我们现有的客户使用了类似 Silverlight 的 WPF 项目。我的工作是修复旧代码中的漏洞,而没有人能够精通这些代码。该应用程序与 Windows 中的其他程序进行交互,因此无法预测在不同环境下可能出现什么问题。
我遇到了以下问题:
1. 程序由于未捕获的异常而停止工作。 2. 很难理解出了什么问题以便修复漏洞。我们的客户通常会通过发送屏幕截图来报告错误,但很难看出发生了什么。
我的处理办法是:
1. 对“用户和系统端点”上的异常(例如按钮单击、拖放、导航命令等)进行捕获。对于这些异常,我准备了一个名为 "OopsBox" 的类,使得每次catch只需要写一行代码处理异常。每一个catch都有尽可能友好的信息,并且可以隐藏脏东西。该框也用于期望的错误消息,并且在这些情况下,没有展开按钮和脏东西可显示,因为我们已经知道出了什么问题。
2. 我们得到了以下收益: - 用户在错误不严重的情况下更容易找到解决方法。 - 当某些意外行为被报告时,更容易理解出了什么问题。 - OopsBox 最初使用频率很高,但我相信产品现在正在更快地稳定下来,并且Oops-boxes变得更加稀有。 - 直到今天,当客户出现问题时,我会通过电子邮件获取调用堆栈。
这样做的代价是: - 对所有用户和系统端点进行大量的遍历。 - 必须重写一些逻辑才能将catch放在正确的位置。
总结:
  • 在任何损害发生之前,应该先捕获异常,例如将用户从上下文中扔出来,并在合适的级别进行处理。

  • 当用户运行您的程序时,如果发生意外情况,请确保有一种方式可以指示您开始查找的位置。我通过捕获我为此目的选择的“用户和系统终点”上的未处理异常来实现此目的。

  • 无论是否出现错误框,请尝试找到一种方式在出现问题时不使用户失去上下文。虽然这在所有情况下都很难实现,但当它发生时会导致严重后果。


6
您可以使用Application.ThreadException和AppDomain.CurrentDomain.UnhandledException属性捕获未处理的(和线程)异常。
您的Main方法可能如下所示:
[STAThread]
static void Main() { 

    if (Debugger.IsAttached) {
        Run();
        return;
    } 

    Application.ThreadException += ApplicationThreadException;
    AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
    Run();
}

请注意调试器检查,这样调试器在开发时可以捕获这些异常。

Run函数非常简单。

    static void Run() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }

然后是两个异常处理程序。

    static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e) {
        ErrorInformationDialog eid = new ErrorInformationDialog(e.Exception.Message, e.Exception);
        eid.ShowDialog();
    }

    static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) {
        ErrorInformationDialog eid = new ErrorInformationDialog(e.ExceptionObject as Exception);
        eid.ShowDialog();
    }

ErrorInformationDialog 是我设计的一个表单,用于显示错误通知和提供报告错误的指导。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接