所以最好使用try/catch

本文关键字:try catch | 更新日期: 2023-09-27 18:37:20

什么时候最好使用尝试和捕捉? 当我使用尝试和捕捉回答问题时,我得到了愤怒的回应(有些甚至是 -1 我......我用谷歌搜索了一下,找到了这篇文章,还有这个堆栈溢出问题。

我举一些例子:

  1. 我有一个包含时区 ID 的下拉列表,当用户选择他的时区时,我正在更新数据库。在其他应用程序中,我正在从数据库中提取此值并重新计算用户当前时间和日期。有一个选项是数据库中的数据拼写错误(数据库中的硬编码更改或错误)。在我正在使用的用户日期时间的转换方法中尝试和捕获,有些人告诉我这是错误的!我可以使用 for 循环检查数据库中的值,但每次转换日期时间时都会花费更多......

  2. 我必须使用以下代码声明 XML 文件的格式是否正确:

    protected bool IsValidXML(string xmlFile)
    {
        try
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlFile);
        }
        catch(XmlException ex)
        {
            ///write to logger
            return false;
        }
        return true;
    }
    

    我看不到任何其他方法来检查 xml 文件。

  3. 有时我的应用程序上有一部分,我正在写入一个文件。 写入文件可能会导致执行,原因有很多,其他一些进程在写入或其他时使用此文件。 所以通常我使用以下代码:

     using (StreamWriter w = new StreamWriter(fs))
     {
         try
         {
             w.Write("** (Line) " + someValue + " **" + Environment.NewLine);                       
             w.Flush();                       
         }
         catch(IOExeption ex){}
         finally
         {
             w.Close();   
         }
     }
    

总之,我看到了一些使用尝试和捕捉的方法和不使用的方法。我看到的文章中的一句话说,如果发生异常,您需要了解它。 ,但是在处理通用应用程序时,大多数时候我知道会发生异常,但大多数时候我真的不知道为什么会发生,所以我之前无法抓住它(就像我写的例子一样), 所以什么时候最好使用尝试和捕捉

在 ASP.NET 的同一关卡中,页面有一个错误事件,您可以像这样捕获该事件:

this.Error += new EventHandler(Page_Error); //this = instance of System.Web.UI.Page

事件是否与尝试捕获问题相同?

所以最好使用try/catch

如何处理异常取决于异常的性质以及异常发生的上下文。

聪明的人写了关于这个主题的优秀文章,我当然可以推荐:

  • 如何设计异常层次结构 作者:Krzysztof Cwalina
  • 埃里克·利珀特(Eric Lippert)令人烦恼的例外
  • API 设计神话:例外是 Krzysztof Cwalina 的"异常错误"

关于您的示例:

在情况 1 中,您可能确实想要防御。但是,请确保您在该捕获块中做了一些明智的事情。

案例 2 看起来很合理,但您正在阅读 XML 文档只是为了将其丢弃。也处理它不是更有意义吗?

在情况 3 中,您使用的是 try final,这绝对与 try catch 不同。在您的特定示例中,您甚至不需要它,因为 using 语句已经确保文件将被关闭。

从个人的角度来看,我一直认为任何可能出错的东西都会出错,并相应地编写我的异常处理策略。 我对其他代码的主要错误之一是,当您遇到一个很容易被捕获的未经处理的异常时 - 它看起来很混乱,如果它是生产代码,那么它表明完全缺乏对程序如何工作以及可能出错的事情的了解。

我的方法可能矫枉过正,但是如果您正在做的事情可能会引发错误,那么它应该被捕获。 我不太喜欢让异常在堆栈中级联并在顶层捕获 - 我更喜欢在源中捕获它们,记录它们,然后,如果应用程序允许它继续,或者最坏的情况是优雅地失败并让用户(或其他开发人员)了解出了什么问题或原因。

对于Web应用程序,我们使用的方法略有不同。 错误(堆栈跟踪等)被记录下来,以便授权人员可以看到它,并且用户会收到错误的精简版本,该版本告诉他们出了什么问题,但没有具体细节。

反正这是我的两便士。 我不确定这种方法是对还是错,但它对我们有用,可以帮助我们生成更健壮的代码。

在这个

答案中,对你使用 try/catch 的批评不是反对一般使用 try/catch,而是反对使用它的特定方式。

  • 您应该捕获异常对象(即使用 catch(SomethingHappenedException e),以便获得有关出错的可用信息。

  • 您应该捕获特定的异常,而不是所有异常。在 DateTime 示例中,我会尝试查找我的每个调用可能引发的异常。然后,我将尝试确定是否有某种方法可以在不使用异常的情况下捕获这些错误 - 该代码中可能捕获的异常之一是 ArgumentNullException。这是一个例外,但我应该能够通过首先检查我没有传递空区域 ID 来处理流中的问题。
    最后,如果无法在程序的正常流程中处理这些情况,我会捕获可能合理发生的特定异常,并尽可能接近异常的来源。

这似乎需要付出更多的努力,但它确实为您节省了调试时间!

例如 1,查看代码会很有帮助。如果没有更具体的想法,就很难发表评论。

例如 2,该代码的问题在于它完全隐藏了任何错误条件。当然,我们会找出 xml 文件是好是坏......但是为什么 XML 是好是坏呢?我们无法知道。这并不是说尝试/捕获不好:而是整个事情写错了水平。只需编写代码来读取 xml 文件,并围绕该代码处理错误。

例如 3,您再次吞下任何有用的异常信息,实际上根本没有对您的 try/catch 执行任何操作finally块中的.Close()调用是完全不必要的,因为当流由using块释放时,完全会处理关闭流。

总之,我认为你在这里需要学习的不是尝试/捕获块不好。而是吞下异常信息是不好的。

我想我可以用你关于尝试的问题来总结人们过去遇到的问题......捕获,并提供一些将来应该对您有所帮助的清晰度。

前两个示例是由数据验证错误引起的。在将数据传递给转换函数(示例 1)或尝试写入 XML 文件(示例 2)之前,应检查数据是否存在已知的验证错误。

异常处理存在大量开销,因此应仅在绝对必要时发生。尝试...捕获模式设计用于处理意外(异常)错误,而不是标准数据验证。

示例 3 几乎是正确用法。在这种情况下,可能会发生您无法做好准备的意外事情,例如 IOException。捕获特定异常被认为是不良形式,因为它可能导致多个捕获块或错过处理。捕获泛型 Exception 对象更好,异常处理代码可以确定和处理异常的确切类型。

您的尝试...catch 块也应该封装流编写器,因为最佳实践是只尝试一次......按方法捕获。如果您使用尝试...catch,它必须始终包含异常处理代码。空的捕获块或空的最终块是糟糕的形式,对代码或任何试图在你之后维护它的人都没有帮助。

    try
    {
       using (StreamWriter w = new StreamWriter(fs))
       {
           w.Write("** (Line) " + someValue + " **" + Environment.NewLine);                       
           w.Flush();                       
       }
    }
    catch(Exception ex)
    {
        //exception handling code here
    }
    finally
    {
       //any clean up code here. The using statement makes it unnecessary for the streamwriter
    }

希望所有这些都有助于回答一些问题并为问题带来一些清晰度。

根据我的经验,任何外部操作(例如与数据库或文件系统交互,或使用第三方组件)都应该有一个 try catch 块。在我自己的代码中,我总是尝试在方法中添加保护子句以限制我自己的代码产生的异常数量,例如,如果您知道数据库不会接受 person 对象上的空名字,则应在任何 save 方法的顶部添加一个保护子句。

简而言之,不要依赖异常来告诉您代码出错的地方,而是首先尝试降低异常的可能性