【问题标题】:C# Nested Try Catch statements or methods?C# 嵌套 Try Catch 语句或方法?
【发布时间】:2010-10-14 09:42:09
【问题描述】:

简单的最佳实践问题。

你应该嵌套 try catch 语句还是只使用方法。

例如,如果您有一个打开文件的方法确实有效并关闭文件,那么您将在 try catch 之外进行打开和关闭,或者更确切地说,在 finally 块中进行关闭。

现在,如果您的 open 方法失败,该方法会断言正确吗?那么你应该将它包装在一个 try catch 块中还是应该从另一个方法调用它,而这又是一个 try catch 块?

【问题讨论】:

  • 示例代码将有助于说明您的问题。
  • 任何用于说明问题的示例(更好的真实)代码?

标签: c# error-handling methods


【解决方案1】:

取决于您要执行的操作,但在大多数情况下,嵌套的 try/catch 表示函数过于复杂(或不太了解异常如何工作的程序员!)。

在打开文件的情况下,我会使用 IDisposable 持有者和 using 子句,因此不需要任何显式的 try/catch。

【讨论】:

    【解决方案2】:

    这是一个风格问题,但对我来说,我尽量不要在一个方法中嵌套多于一层的 try/catch/finally。在您进行嵌套尝试时,您几乎可以肯定违反了 1 function = 1 操作原则,应该使用第二种方法。

    【讨论】:

    • 我认为,即使不是大多数开发人员,也不会是风格问题。这将是一个不理解 .NET 中的异常的问题,并认为它们需要捕获每个异常,就像在 Java 中一样。在大多数情况下,最好让异常传播。
    【解决方案3】:

    在打开文件的方法的上下文中,我会使用 using 语句而不是 try catch。 using 语句确保在发生异常时调用 Dispose。

    using (FileStream fs = new FileStream(file, FileMode.Open))
    {
        //do stuff
    }
    

    做同样的事情:

    FileStream fs;
    try
    {
         fs = new FileStream(file, FileMode.Open);
         //do Stuff
     }
     finally
     {
            if(fs!=null)
               fs.Dispose();
     }
    

    【讨论】:

    • 关闭,但 try/finally 代码与使用代码不太匹配。您还需要将其包装在匿名范围块中。
    【解决方案4】:

    大多数时候,我会将嵌套的 try/catch 块分解为函数。但是我有时会编写代码来捕获和记录我的应用程序抛出的所有未捕获的异常。但是如果日志记录代码失败怎么办?所以我有另一个尝试/捕捉,只是为了防止用户看到默认的 .NET 未处理异常对话框。但即使是这段代码也可以很容易地重构为函数,而不是嵌套的 try/catch 块。

    try
    {
        try
        {
            DoEverything(); 
        }
        catch (Exception ex)
        {
            // Log the exception here
        }
    }
    catch (Exception ex)
    {
        // Wow, even the log is broken ...
    }
    

    【讨论】:

    • 如果您的日志记录被破坏,那么您应该让异常传播,以便用户可以抱怨您的日志记录被破坏!
    • 我仍然可以显示日志记录代码引发的异常。只是想要这样做,而不是让框架错误窗口出现。
    【解决方案5】:

    现在我们有了 lambdas 和类型推断以及其他一些东西,有一个在其他语言中很常见的习语现在在 C# 中很有意义。你的例子是关于打开一个文件,对它做一些事情,然后关闭它。好吧,现在,您可以创建一个打开文件的辅助方法,并确保关闭/处置/清理,但调用您为“做的东西”部分提供的 lambda。这将帮助您将复杂的 try/catch/finally dispose/cleanup 东西放在一个地方,然后一遍又一遍地使用它。

    这是一个例子:

    public static void ProcessFile(string filePath, Action<File> fileProcessor)
    {
      File openFile = null;
    
      try
      {
        openFile = File.Open(filePath); // I'm making this up ... point is you are acquiring a resource that needs to be cleaned up after.
    
        fileProcessor(openFile); 
      }
      finally
      {
        openFile.Close(); // Or dispose, or whatever.
      }
    }
    

    现在,此方法的调用者不必担心如何打开文件或关闭/处置它。他们可以这样做:

    Helpers.ProcessFile("C://somefile.txt", f => 
     {
       while(var text = f.ReadLine())
       {
         Console.WriteLine(text);
       }
     });
    

    【讨论】:

    • @alhambraeidos,如果我理解正确,是的,你绝对可以。您可以创建一个名为“ForEachLine”的方法,该方法打开文件,执行 while 循环以逐行读取它,并在每一行调用您传入的函数。
    • 像这样:MyHelperClass4Files.ForEachLine(f); ??
    • 像这样: Helpers.ForEachLine("@c:\somefile.txt", aLine => Console.WriteLine("The next line says: " + aLine); 这将输出所有行文件到控制台,每行前面都有“下一行说:”,它还可以确保文件被正确关闭。
    【解决方案6】:

    您在哪里有不一定属于它自己的单独功能的相关代码呢?那么这会是正确的吗?

    try
    {
      // Part 1 Code Here
    
      try
      {
        // Part 2 Code Here
      }
      catch (Exception ex)
      {
        // Error from Part 2
      }
    }
    catch (Exception ex) 
    {
      // Error from Part 1
    } 
    

    【讨论】:

      【解决方案7】:
      try 
      {
        ----
      }
      catch
      {
         try
            {
                 ---
            }
         catch
            {
              ---
            }
      }
      

      【讨论】:

      • @choopage-JekBao 可能是因为它没有关于为什么这应该是公认的答案的支持上下文。简短的描述/代码 cmets 不会造成伤害。
      【解决方案8】:
      //create a switch here and set it to 0 
      try
      {
          DoChunk1(); 
          //looks good. set the switch to 1
      }
      catch (Exception ex)
      {
          // Log the exception here
      }
      

      // 检查开关,如果此时它仍然为零,那么你可以在这里暂停你的程序;否则将开关设置回零并执行下一个 try catch 语句。完全同意如上所述将它们分解

      试试 { DoChunk2(); //看起来不错。将开关设置为 1 } 捕捉(例外前) { // 在此处记录异常 }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-23
        • 2011-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-30
        相关资源
        最近更新 更多