【问题标题】:Eating Exceptions饮食例外
【发布时间】:2011-04-27 17:42:12
【问题描述】:

我正在解析一个不时包含 MalFormed 数据的文件。

它正在抛出异常,

我想从异常中恢复并忽略格式错误的数据。

最好的方法是什么?

try{
// parse file
}catch(Exception){
//eat it.
}

*编辑:*我想,我的问题没有被很好地理解。我想从异常中恢复,任何异常,我不希望我的程序停止。但要继续。

【问题讨论】:

  • 捕获一般异常是个坏主意。您应该只捕获您可以处理的特定异常。这已经在 Stack Overflow 上多次提出。
  • 您想忽略当前解析中的所有数据,还是只忽略错误的行/元素/字符?
  • 在这里,我认为这将是关于从普通的意大利辣香肠披萨转向中餐。 (当送货员知道你的名字、你的工作以及你正在从事的项目时,这很糟糕吗?)

标签: c# .net exception error-handling


【解决方案1】:
try{
   // parse file
   }
   catch(Exception){
     //eat it.
   }
   finally 
   {
      //cleanup  must ... release system resources here (e.g. stream.Close() etc)
      // code here always executes...even if the exception is unhandled

   }

// code will resume execution from this point onwards...

【讨论】:

    【解决方案2】:

    我想你要问的是:

    逐行解析文件时,有时当前行包含格式错误的数据,这会导致代码中引发异常。也许您只需要构造您的代码,使 try/catch 仅围绕解析代码,而不是行读取代码。例如:

    using System;
    using System.IO;
    using System.Windows.Forms;
    
    public void ParseFile(string filepath)
    {
        TextReader reader = null;
    
        try
        {
            reader = new StreamReader(filepath);
    
            string line = reader.ReadLine();
            while (!string.IsNullOrEmpty(line))
            {
                try
                {
                    // parse line here; if line is malformed, 
                    // general exception will be caught and ignored
                    // and we move on to the next line
                }
                catch (Exception)
                {
                    // recommended to at least log the malformed 
                    // line at this point
                }
    
                line = reader.ReadLine();
            }
        }
        catch (Exception ex)
        {
            throw new Exception("Exception when trying to open or parse file", ex);
        }
        finally
        {
            if (reader != null)
            {
                reader.Close();
                reader.Dispose();
            }
            reader = null;
        }
    }
    

    外部的 try/catch 块用于在尝试打开或读取文件时正确关闭读取器对象。内部的 try/catch 块用于吞下如果读取的数据格式错误且无法正确解析时引发的异常。

    不过,我几乎同意其他所有人的观点。仅仅吞下异常可能并不好。至少,我建议您将其记录在某个地方。

    【讨论】:

    • 在外部捕获中,您需要使用throw; 而不是将原始异常包装在新异常中,以保留调用堆栈。此外,如果您使用using(reader = new StreamReader(filepath)),那么您无论如何都不需要那个外部异常块。
    • @hemp 值得一提的是,throw; 不会总是保留调用堆栈,throw ex; 更不用说。见:weblogs.asp.net/fmarguerie/…
    • 你是对的@Dan,在同一个函数中抛出、捕获和重新抛出异常的情况下,堆栈跟踪将只显示有关它被重新抛出的位置的信息。在实践中,这种情况很少见。
    【解决方案3】:

    我有一种感觉,你看到黑白之类的东西,感觉不对。是的,大多数时候,在验证输入时捕捉所有内容并马虎是不好的,但是不总是。这很可能是一个特例。我不知道要解析什么样的文件,但例外可能是正确的。

    在我们决定什么是最好的之前,请告诉我们更多细节:)

    【讨论】:

      【解决方案4】:

      如果您希望它只为解析特定的错误抛出一种或两种特定的异常类型,那么捕获一般异常是一个坏主意。通常最好捕获每个特定的异常类型并独立处理它,这样您的代码就不会抑制任何其他(可能是意外的)错误(例如,如果文件丢失,或者网络连接超时,应该在就像文件包含损坏的数据一样?)

      但是,如果您有意/想要捕获所有可能的错误并优雅地继续,那么捕获一般异常是一个好主意。如果对所有错误类型的处理相同,则可能会发生这种情况(例如,“如果出于任何原因,我无法读取此首选项值,我将返回默认值 5” - 这比您的程序崩溃要好得多,因为您没有t意识到它可能会由于网络超时而引发异常)。如果使用得当,这种方法可以使您的程序防弹 - 但如果使用不当,您可以抑制需要了解和修复的错误,这可能会非常痛苦。

      在抑制任何异常时,您应该始终仔细考虑错误报告 - 您是否应该告诉用户您遇到了问题?您是否应该将其记录在跟踪文件中,以便当客户抱怨某些事情无法正常工作时,您可以追溯问题的根源?还是应该默默地忽略它?只是要小心,因为过分热心的压制可能会导致很难弄清楚为什么节目会表现得不可预测。

      【讨论】:

        【解决方案5】:

        一般来说是这样的:

        try
        {
            // parse file
        }
        catch (FormatException)
        {
            // handle the exception
        }
        finally
        {
            // this block is always executed
        }
        

        您应该避免捕获一般的Exception 情况,而是捕获特定的异常,无论它可能是什么。

        【讨论】:

          【解决方案6】:

          这里有一些很好的背景信息: Is there any valid reason to ever ignore a caught exception

          简短的回答:以这种方式使用异常的成本很高。如果可能的话,在发送它进行处理之前测试输入并在那里忽略而不是忽略异常。

          同时确保你没有撒网,没有吃掉你可能想知道的合法例外。

          【讨论】:

            【解决方案7】:

            简而言之,您可能不应该为此使用异常。像 TryParse 这样返回 false 的东西效率更高,也更容易从中恢复。异常处理有点生硬。

            MSDN Guidance on Exception Handling

            【讨论】:

            • TryParse 仅在您阅读一些提供 TryParse 方法的原始类型时才相关。如果您从文件流中解析并且该文件丢失,则不可能没有异常的“TryParse” - 您将需要异常处理 somewhere 来处理 FileNotFoundException。
            • @Jason,我认为你在挑剔。 TryParse 方法在您编写任何时候都可用。如果你从来没有写过,你可能做错了。 MSDN 将其称为"Tester-Doer" pattern 并鼓励将其作为首选实践(过度处理异常)。不要打开文件来解析它;相反,首先测试它是否存在,然后尝试打开它进行读取,然后尝试解析打开的流。如果您遵循该模式,则不需要 FileNotFoundException,除非您决定抛出一个。
            • @hemp:如果您测试一个文件是否存在,然后尝试打开它进行读取,当另一个线程或另一个进程在您的 IsExists() 调用和实际之间删除文件时,您将收到 FileNotFound 异常打开文件。无论这种情况多么罕见,除非您处理可能的异常,否则您的代码是有缺陷的。问题是你不能总是避免异常处理(我很想这样做)。是的,您可以编写 TryParse 方法,但要正确编写它,您几乎可以肯定必须在其中包含一些异常处理 - 您只是在移动 catch 的站点{}。
            • @hemp:没错。因此,如果您正在编写一个 TryParse(),根据定义,它是一个您不希望抛出异常的方法,您是否应该忽略 all 异常并让它们命中您的调用者?我同意你的大部分理想,但不幸的是,很多 .net 方法会抛出异常以传回我所说的“状态信息”(FileNotFound 就是一个很好的例子),所以不幸的是,要编写健壮的代码,异常处理通常是不可避免。我不同意,但如果你调用库函数,那么抛出异常的位置/方式不是我的选择。
            • @hemp:同样,减少异常发生的机会并不能免除您处理它的责任。 “减少机会”只会使错误更具破坏性,并且在何时发生时更难找到。
            【解决方案8】:

            这行得通 - 如果您想查看导致异常发生的数据是什么并使用它来改进您的解析逻辑,也许您也可以记录错误。

            【讨论】:

              猜你喜欢
              • 2017-04-28
              • 1970-01-01
              • 2013-03-27
              • 1970-01-01
              • 2018-03-01
              • 1970-01-01
              • 2010-12-09
              • 1970-01-01
              • 2010-11-19
              相关资源
              最近更新 更多