有没有办法在try / catch块之外获取最后抛出的异常?

时间:2013-06-24 12:48:07

标签: vb.net winforms .net-4.0 exception-handling

修改:

致所有回答者和评论者:请专注于提供我要求的解决方案,而不是提供重构方法。为简洁起见,下面提供的代码是一个非常简洁的例子。我已经在下面说过,这种类型的代码存在于整个应用程序的20或30个位置,如果存在更简单的解决方案,我选择不移动/合并/重构任何代码。

原始问题:

首先,这里简要介绍一下:我们有一个由离岸团队开发的应用程序。此应用程序的目的是在各种数据库表上运行每夜维护。它是一个WinForms应用程序,但它更像是一个控制台应用程序,因为它只是1)在Form1_Load中执行一个方法,然后2)调用End来关闭程序。

问题是错误电子邮件通知不起作用,所以我被指控修复它的任务。请考虑以下代码:

Try
    'This inner Try/Catch is actually code in another method
    Try
        'Run some code here
    Catch ex As Exception
        'Errors are logged silently to text file here
    End Try
Catch ex As Exception
    'Code to email exception details is here
End Try

问题是在内部Try / Catch中抛出并处理异常。因此,在外部Try / Catch中处理没有例外,因此没有发送电子邮件通知的原因。

有人可能会说要在内部Catch中添加Throw ex,但请记住,代码中有大约20或30个位置可以像这样处理异常。我正在做的决定是让它现在正常工作,而不是进行那种开发工作。因此,我想办法以某种方式获取应用程序抛出的最后一个异常。这样,我可以将一个Finally块添加到外部Try / Catch并执行以下操作:

Finally
    If Not Application.GetLastException() is Nothing Then
       SendErrorEmail(Application.GetLastException())
    End If
End Try

2 个答案:

答案 0 :(得分:5)

因此,如果我理解正确,您的应用程序将捕获所有异常并将其静默记录到文件中。

您希望更改行为,以便在程序结束时获取抛出的最后一个异常(如果有),并发送包含该异常详细信息的电子邮件。但抛出的最后一个异常不存储在任何地方。

并且您希望在不修改处理异常的代码的情况下更改此行为。

无法做到。您如何期望在不改变程序行为的情况下改变程序的行为?你问的是不可能的。 (并且,不,甚至Yoda都不能将这个特定的X翼从沼泽中拉出来。)

没有运行时属性可以自动保存抛出的最后一个异常。

您必须对捕获异常的代码进行某些修改。你说代码采用这种通用格式:

Try
    'This inner Try/Catch is actually code in another method
    Try
        'Run some code here
    Catch ex As Exception
        'Errors are logged silently to text file here
    End Try
Catch ex As Exception
    'Code to email exception details is here
End Try

我认为问题出在内部Catch块中。在我看来,如果将错误记录到文本文件有共同的代码,那么该代码应该在一个单独的方法中。如果是,则修改该方法以将最后一个异常保存在GetLastException方法可以访问的属性中。如果没有一个处理异常日志记录的常用方法,那么你必须在每个地方进行更改。

评论者是正确的:一般的“抓住所有例外”几乎总是一个坏主意。特别是当“处理”包括记录和继续时。当你发现一些随机异常时,你不知道程序的状态是什么。数据很可能已损坏且程序状态不稳定。 “记录并继续”只会使问题变得更糟,并且可能导致各种有趣的副作用,如数据损坏,无限循环,死锁等。

这里你最好的做法是重构代码。实际上,最好的方法是将其发回海外开发商并告诉他们做得对。但这可能要求太多了。

答案 1 :(得分:2)

我参加这个派对已经很晚了,但你可以尝试这种相当丑陋的做事方式。

首先通过添加LastException属性和GetLastException函数see here for details来扩展Application类。

其次在每个内部Catch块中添加一行并设置LastExcepotion属性:

Application.LastException = ex

你去了,不需要重构所有离岸代码。