【问题标题】:What's the point of nested try-catch block?嵌套的 try-catch 块有什么意义?
【发布时间】:2011-04-15 20:40:02
【问题描述】:

这是一个伪代码:

try
{
  TextReader tr = new StreamReader("filename");
  try
  {
    string content = tr.ReadToEnd();
  }
  catch(Exception ex)
  { /*Show error message*/ }
  finally
  { tr.Close();}
}
catch(Exception ex)
{ /*Show error message*/ }

好的,该代码是一本书的示例。我不明白为什么要使用嵌套的 try-catch 块。

如果

string content = tr.ReadToEnd();

出错了,那么外部 catch 应该捕获异常吧?所以我看不出在这条线上使用额外的 try-catch 有什么意义!

如果您在这里发现任何误解,如果您能指出,我会很高兴!

还有什么情况下可以合理使用嵌套的 try-catch?

【问题讨论】:

标签: c# try-catch


【解决方案1】:

您的示例与只有一个外部捕获的类似代码之间的差异:

1) 如果内部块抛出异常,则在调用Close() 之前打印消息。如果Close() 还包含日志记录,这可能很重要。

2) 如果一个内部异常被抛出并被捕获,然后在 finally 块中Close() also 抛出,你得到两个异常,你处理两个异常。只有一个 catch 块,如果 Close() 抛出,那么接下来发生的事情可能取决于语言,但您不会打印两条错误消息。我希望第二个例外能够取代第一个例外,但我不发誓这就是 finally 的所有语言,甚至我使用过的所有语言都会发生的情况......

3) //Show error message 只是一个评论,它什么也不做。作者的意图可能是在两种不同情况下显示不同错误消息。内层会说“读取失败”,而外层会说“无法打开文件”。或类似的东西。要仅使用一个 catch 块来实现这一点,您可以设置并检查一个指示进度的标志(这可能不会使代码比两个 catch 块更简单),或者您可以依靠异常本身来包含适当的错误消息 (在这种情况下,祝您好运,将您的本地化框架与内置或第三方库中的异常抛出函数集成)。

请注意,即使您只有一次捕获,您仍然需要两次尝试,因为finally。这不好:

try {
    TextReader tr = new StreamReader("filename");
    string content = tr.ReadToEnd();
} catch(Exception ex) {
    // show error message
} finally {
    tr.Close();
}

因为从这种语言的外观来看,tr 不会在 finally 块的范围内,所以我们不能在那里关闭它。我们必须在处理创建它的块内部关闭它。或许我们可以这样处理:

TextReader tr = null;
try {
    tr = new StreamReader("filename");
    string content = tr.ReadToEnd();
} catch(Exception ex) {
    // show error message
} finally {
    if (tr != null) {
        tr.Close();
    }
}

但是与原始代码相比,这并没有真正简化很多事情,我们仍然需要处理 2-3 的差异,现在我们根本不处理来自 Close() 的异常。因此,对于许多目的而言,具有多个 try/catch 的原始代码会更好。

【讨论】:

  • 我认为重要的一点是#2。外部 try catch 捕获新 StreamReader 上的异常,例如 FileNotFound 等,它还封装了 tr.close() 上的异常。这留下了用于处理读取错误的内部 try catch,而不是“连接”类型错误。
  • @FoneyOp:也许吧,尽管很难用示例代码来说明它应该说明什么,这就是我提到所有东西和厨房水槽的原因。当我阅读一个流时,我通常不会太担心Close() 抛出,所以我不确定它在这里是否重要。如果我在写,Close() 上的错误确实会变得非常有趣,所以也许这段代码应该可以很好地设置我们的流处理。
  • 同意。或者可能是数据库连接等。
【解决方案2】:

如果string content = tr.ReadToEnd();出错了,那么外部catch应该捕获异常吧?

不,内部catch 将捕获它并显示错误消息。然后执行内部的finally。然后外部try 块完成,没有任何异常处理,因为内部try-catch 块已经处理了它。

【讨论】:

    【解决方案3】:

    我使用的一个例子是当我需要处理特定类型的异常时:

        try
        {
    
               //...
               //IMPORTANT CODE HERE
               //....
            try
            {
                // Read in non-existent file.
                using (StreamReader reader = new StreamReader("not-there.txt"))
                {
                reader.ReadToEnd();
                }
            }
            catch (FileNotFoundException ex)
            {
               //Do something important here
            }
           //...
           //MORE IMPORTANT CODE
           //...
        }
        catch(Exception ex) ///An Exception I'm not expecting
        { //oops...handle gracefully here
     }
    

    【讨论】:

      【解决方案4】:

      您希望尽早捕获异常。让事情冒泡到外部异常是不好的做法。记住规则:尽早失败,经常失败。

      【讨论】:

      • 我不同意这一点。 如果你可以在不同的情况下有用地做不同的事情,那么你应该这样做。如果你会以任何一种方式做同样的事情,那么让事情冒泡到你的代码中最能处理错误的点是不好的做法。 “提前失败”意味着尽快抛出异常,但在你可以用它做一些有用的事情之前,你永远不应该捕获异常。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-30
      • 1970-01-01
      • 2023-03-19
      • 2018-11-07
      • 1970-01-01
      • 2022-01-01
      相关资源
      最近更新 更多