VB.NET尝试使用多个Catch块捕获

时间:2013-01-17 15:05:53

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

这是一个非常奇怪的问题。我们有一个包含多个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中完成。

3 个答案:

答案 0 :(得分:15)

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块的末尾重新抛出。

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

答案 1 :(得分:5)

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

<强> PROOF

如果你写:

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

并且您在{em> Quickwatch模式中查看ex评估为Nothing

BUT

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

答案 2 :(得分:-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块应该在广义块之前出现。否则编译器将显示编译错误。 Multiple Catch Blocks

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

编辑: 似乎可以完全避免我在另一篇文章中读到的这个异常。而且似乎最好避免异常,而不是不处理它。 Handling ThreadAbortException

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

编辑: 为了在评论中直接设置一些人,我创建了一个非常简单的测试程序,看看这确实是一个bug。我的发现是捕获块完美地工作。似乎遵循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代码的最佳方式。