【问题标题】:What is the point of this Catch statement?这个 Catch 语句的意义何在?
【发布时间】:2009-09-22 17:12:09
【问题描述】:

我在遗留代码中看到了这一点。如果有的话,在 Catch 中单次 Throw 的目的是什么?

       Try
           'Some Oracle access statement
       Catch err As OracleClient.OracleException
            Throw
       Finally
          'Do something
       End Try

结果是否与未捕获原始错误相同?您是否会使用不带参数的 Throw 语句重新抛出原始错误,通常是在先执行某些操作之后?

【问题讨论】:

    标签: vb.net error-handling


    【解决方案1】:

    我在调试时经常使用这种模式;我将在 throw 语句上设置一个断点,以便检查 err。不过不确定是否还有其他充分的理由这样做。

    【讨论】:

      【解决方案2】:

      许多人认为这是一个空操作,但事实并非如此。如果你有这个程序:

      Module Module1
          Function Filter() As Boolean
              Console.WriteLine("1")
              Return True
          End Function
      
          Sub Thrower()
              Try
                  Throw New Exception("x")
              Finally
                  Console.WriteLine("3")
              End Try
          End Sub
      
          Sub NoCatch()
              Try
                  Thrower()
              Finally
                  Console.WriteLine("2")
              End Try
          End Sub
      
          Sub WithCatch()
              Try
                  Thrower()
              Catch ex As Exception
                  Throw
              Finally
                  Console.WriteLine("2")
              End Try
          End Sub
      
          Sub Caller(ByVal method As Action)
              Try
                  method()
              Catch ex As Exception When Filter()
              End Try
          End Sub
      
          Sub Main()
              Console.WriteLine("No Catch")
              Caller(AddressOf NoCatch)
              Console.WriteLine("With Catch")
              Caller(AddressOf WithCatch)
          End Sub
      End Module
      

      输出是

      No Catch
      1
      3
      2
      With Catch
      3
      1
      2
      

      编辑:这实际上很重要的一种情况: Thrower 和 NoCatch 函数位于同一个组件中,该组件被推进。 Caller 方法不受信任且是恶意的。现在假设 Thrower 方法使用 WindowsIdentity 模拟另一个用户,不受信任的程序集不允许这样做。然后它依赖于 using 块(= try/finally)来模拟用户,但它会引发异常。这意味着恶意程序集在执行 Filter 方法期间以模拟用户身份运行。如果声明权限,也许这也可以工作,但我不确定。

      【讨论】:

      • 有趣...但具体会改变什么吗?在什么情况下调用 finally 子句的顺序很重要?
      • 如果您有一个程序,其唯一规范是将数字 1、3、2 写入控制台(按此顺序)并尝试使用上面的代码解决它,这显然很重要 :)跨度>
      • 要注意的另一件有趣的事情是,过滤器在某些情况下可能允许记录异常,这些异常最终会被覆盖而不会被捕获。 P1 [in vb.net] 在Catch ZooException When ZooFilter() 内调用P2,它在try/catch MooException 块内调用P3P3try/finally 块内调用 P4,其 finally 子句抛出 MooExceptionP4 抛出 ZooException。即使P1 中的过滤器看到ZooException 并决定捕获它,异常也可能在它到达之前消失。
      【解决方案3】:

      看起来它被用来冒泡错误。虽然在这种情况下通常会在 catch 语句中放入更多内容,而不仅仅是 throw(即日志记录、警报等),但它允许使用 finally 语句进行一些清理,然后将错误冒泡到下一个级别。如果没有 try/catch,如何在这个范围内编写清理代码?正如有人已经提到的那样,抛出语法(没有 ex)正在保留堆栈跟踪。

      【讨论】:

        【解决方案4】:

        这没什么。有正确就扔。

        您可以删除 catch,但如果 Final 中的评论不止一条,您会想离开 try。

        【讨论】:

        • 即使在 try 块中,异常也会冒泡吗?
        【解决方案5】:

        它捕获错误然后再次抛出它。我不明白这一点,因为你可以做 Try...Finally 没有 Catch 子句...

        jenningj 有一个好点子,它可以用来通过断点检查错误,但它不应该出现在生产代码中。

        【讨论】:

          【解决方案6】:

          使用 throw 不带参数的主要原因是它会保留原始堆栈跟踪。

          除了在 throw 语句上放置断点之外,您还可以更改 VS 设置以中断 oracle 异常,这比在所有地方添加断点要容易得多

          【讨论】:

            【解决方案7】:

            这将重新抛出相同的错误。它将允许您在 finally 块中进行工作,同时将错误重新抛出给调用者

            编辑

            显然,异常会在没有捕获和重新抛出的情况下冒泡,因此不需要它。我的立场是正确的。

            【讨论】:

            • 同意。它允许发生异常,但 finally 代码允许您在将异常传递回调用进程之前执行诸如关闭连接或回滚事务之类的操作。
            • 这个答案意味着你必须有一个 catch 才能有一个 finally,但事实并非如此。 :)
            • 我并不是暗示你需要 catch 来获得 finally 块,我认为你需要 catch 并重新抛出异常才能冒泡。我不知道它会冒泡。
            猜你喜欢
            • 1970-01-01
            • 2016-05-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-12
            • 1970-01-01
            • 2012-01-05
            • 2021-12-25
            相关资源
            最近更新 更多