29

这是一个非常奇怪的问题。我们有一个带有多个 Catch 块的 Try Catch。第一个 Catch 块没有代码,只是一个注释。

Try
  'Some Code
Catch ex As ThreadAbortException
  'Do Nothing
Catch ex As Exception
  HandleException(ex)
End Try

如果抛出除 ThreadAbortException 之外的异常,则如预期的那样,它会被第二个 Catch 捕获。但是,在 VS2010 中单步执行代码时,ex 对象在这种情况下是 Nothing。到目前为止,我们已经找到了两种方法来“修复”这个问题。

修复 1:重命名第一个异常变量。

Try
  'Some Code
Catch tex As ThreadAbortException
  'Do Nothing
Catch ex As Exception
  HandleException(ex)
End Try

修复 2:将任何代码行添加到第一个 Catch 块。

Try
  'Some Code
Catch ex As ThreadAbortException
  Dim i As Integer = 1
Catch ex As Exception
  HandleException(ex)
End Try

在上述任何情况下,如果运行,HandleException 中的代码似乎仍然可以正常运行。这是 Visual Studio 或调试器中的错误吗?还是我们在这里遗漏了什么,上面的第一段代码无效?

这一切都在 .NET 4.0 中完成。

4

3 回答 3

18

Teejay 有正确的答案。

但是,如果您的Catch块为空,则处理此异常完全没有意义。您只想阻止最后一个块捕获它。你可以使用你的方法——但是考虑到有一个空Catch块通常是不可接受的:异常要么不被捕获,要么应该被正确处理;默默地吞下它们必须被视为一个错误。您的案例是此规则的一个例外,但因此需要在代码中记录,否则会混淆细心的维护人员。

好吧,VB 有一个专门针对这种情况的习惯用法:

Try
    ' …
Catch ex As Exception When Not TypeOf ex Is ThreadAbortException
    ' Only executed if `ex` isn’t a ThreadAbortException
End Try

这段代码根本没有捕捉ThreadAbortException到,如果你不想处理它,这是正确的做法:ThreadAbortException 不能被吞下,所以即使你捕捉到它,它也会在Catch块的末尾重新抛出。

请注意,这与 SysDragon 的答案根本不同,后者使用常规If语句,而此处的代码使用语句中的特殊子句Catch作为过滤器。

于 2013-01-17T20:13:16.997 回答
6

这似乎是 VS 的调试器错误。

证明

如果你写:

Try
    Throw New InvalidOperationException("MESSAGE")
Catch ex As ArgumentException
    'Do Nothing
Catch ex As Exception
    Debug.WriteLine(ex)
End Try

你看看exNothingQuickwatch 模式下的评估结果

在控制台中程序正确打印System.InvalidOperationException: MESSAGE

于 2013-01-17T16:16:39.760 回答
-2

好的,让我详细说明...

看来您必须在每次捕获中都有一个“结果”。如果您只是不希望特定捕获发生任何事情,请不要包含它,或者将其移动到代码中的不同位置。

Try
   'Some Code
Catch ex As ThreadAbortException
   'Do something(ex: HandleExceptionSub())
Catch ex As Exception
   HandleException(ex)
End Try

如果您“捕获”异常,则必须对其进行处理。

编辑:

我还发现了这些信息,可以帮助您进一步了解 try catch 的工作方式:

多个捕获块

一个try块可以抛出多个异常,可以使用多个catch块来处理。请记住,更专业的 catch 块应该位于通用的 catch 块之前。否则编译器会显示编译错误。 多个捕获块

这不是调试器的“错误”。调试器旨在帮助您查找和处理所有异常。

编辑:似乎可以从我在另一篇文章中阅读的内容中完全避免此异常。似乎最好避免异常而不是不处理它。 处理 ThreadAbortException

编辑:刚刚在 try 中找到了有关多个 catch 块的更多信息。这来自 MSDN,并指出永远不会到达空白 catch 块之后的 catch 块... Try Catch finally 语句 进一步证明这不是错误,而是强制处理代码中所有异常的预期功能。

编辑:为了让一些人在评论中直截了当,我创建了一个非常简单的测试程序来查看这是否确实是一个错误。我的发现是 catch 块工作得很好。似乎遵循 MSDN 记录的使用多个 Catch 块创建 Try Catch 的方法正如他们所说的那样工作。

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            if (textBox1.Text == "")
            {
                throw new ArgumentNullException("textBox1", "TextBox can not be empty");
            }
            else
            {
                MyString(textBox1.Text);
            }
        }
        catch (ArgumentNullException ex)
        {
            //nothing
        }
        catch (Exception ex)
        {
            MessageBox.Show("Test: " + ex.Message);
        }
    }

    private int MyString(string text)
    {
        return int.Parse(text);
    }

我创建了一个带有按钮和文本框的简单表单。如果文本框为空,我会抛出 ArgumentNullException,并在“MyString”中将字符串解析为抛出“FormatException”的整数。有一个空白的 catch 块,这不是处理“捕获”异常的正确方法确实有效。所以据我所知,这不是一个错误。显然,我唯一能同意 Teejay 和 Konrad 的一点是,您不能使用 try catch 方法捕获和处理 ThreadAbortException。Konrad 的解决方案是编写 try catch 的最佳方式。

于 2013-01-17T15:52:59.367 回答