【问题标题】:Is there a way to get the last thrown exception outside of a try/catch block?有没有办法在 try/catch 块之外获取最后抛出的异常?
【发布时间】:2013-06-24 12:48:06
【问题描述】:

编辑:

致所有回答者和评论者:请专注于提供我要求的解决方案,而不是提供重构它的方法。为简洁起见,下面提供的代码是一个非常精简的示例。我已经在下面说明了这种类型的代码存在于整个应用程序的 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 个位置是这样处理异常的。我正在做的决定是让它现在工作,而不是进行那种开发工作。因此,我寻求一种方法来获取应用程序抛出的最后一个异常。这样,我可以在外部 Try/Catch 中添加一个 finally 块并执行以下操作:

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

【问题讨论】:

  • 捕获特定异常,绝不是 Exception 类型的一般异常。
  • 为什么不检查是否有内容写入日志。
  • 另外,.. 似乎你想在异常情况下做两件事。为什么不只进行一次 try/catch 并在一次 catch 中执行 2 个操作?所以:只需删除外部异常,然后将所有内容从该捕获移动到内部捕获。
  • @JorisVanRegemortel:如果您知道所有可以抛出的异常,那么可以。但是,对于未知的异常,我总是有一个基本的Catch Ex。另外,这段代码不是我写的。
  • 这正是我正在做的。您必须进行重构才能获得解决方案。您粘贴的代码无效。外部异常块永远不会触发。只要摆脱块并将其与内部块合并,你应该有你的解决方案。

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


【解决方案1】:

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

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

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

这是不可能的。您如何期望在不改变程序行为的情况下改变程序的行为?你问的是不可能的。 (而且,不,甚至尤达也无法将这个特殊的 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 方法可以访问的属性中。如果没有处理异常日志记录的通用方法,那么您必须在每个地方进行更改。

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

您最好的做法是重构代码。实际上,最好的做法是将其发回给离岸开发商并告诉他们做正确的事。但这可能问得太多了。

【讨论】:

  • 我将接受您“无法完成”的回答。但是,我不同意不将一般异常处理块作为故障安全措施来报告未说明的异常。此外,此应用程序不会在您正在考虑的上下文中“记录并继续”。此应用程序在 Catch 块中记录所有错误,然后运行 ​​Exit Sub 或再次抛出异常以到达外部 Try/Catch 的 Catch 块。
  • @oscilatingcretin 再一次:你为什么要那样做?只需合并 2 个 catch 块。
  • @JorisVanRegemortel 再一次:这不仅仅是 2 个 catch 块。像这样的块存在于整个应用程序中。如果存在更全球化的解决方案,我选择不通过在整个地方重构它来触发这个应用程序的端到端测试。如果你还有什么要补充的,可以拿去聊天。
【解决方案2】:

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

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

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

Application.LastException = ex

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    • 2019-07-12
    • 2012-02-20
    • 1970-01-01
    相关资源
    最近更新 更多