Exception 指导您的异常处理策略的原则是什么?

Exception 指导您的异常处理策略的原则是什么?,exception,exception-handling,error-handling,Exception,Exception Handling,Error Handling,处理异常涉及到很多相关性。除了低级API(异常包括硬件和操作系统引发的错误)之外,还有一个隐蔽的领域,程序员可以在这里决定什么是异常以及什么是正常情况 您如何决定何时使用异常关于异常,您有一致的策略吗?异常在处理时间上非常昂贵,因此只有在您的应用程序中确实不应该发生的事情发生时才会抛出异常 有时,您可以预测可能发生的情况,并编写代码从中恢复,在这种情况下,可以抛出并捕获异常,记录并恢复,然后继续。否则,它们只应用于处理意外情况并优雅地退出,同时捕获尽可能多的信息以帮助调试 我是一名.NET开发人

处理异常涉及到很多相关性。除了低级API(异常包括硬件和操作系统引发的错误)之外,还有一个隐蔽的领域,程序员可以在这里决定什么是异常以及什么是正常情况


您如何决定何时使用异常关于异常,您有一致的策略吗?

异常在处理时间上非常昂贵,因此只有在您的应用程序中确实不应该发生的事情发生时才会抛出异常

有时,您可以预测可能发生的情况,并编写代码从中恢复,在这种情况下,可以抛出并捕获异常,记录并恢复,然后继续。否则,它们只应用于处理意外情况并优雅地退出,同时捕获尽可能多的信息以帮助调试

我是一名.NET开发人员,对于捕获和抛出,我的方法是:

  • 仅在公共方法中使用try/catch(一般来说;显然,如果您正在捕获特定错误,您将在那里检查它)
  • 仅在抑制错误并重定向到错误页面/表单之前登录UI层

  • 如果语言环境确实有异常的概念,那么它提出的异常不符合所使用语言的规范吗?我在考虑Java中的“被零除”,或者Ada中的约束_错误与C中的完全没有相比

    在选择了一种在其组成中定义了异常的编程语言之后,程序员如何“决定”使用异常

    编辑:或者,与其说“使用”异常,不如说什么时候应该有一个关于“处理”异常的连贯一致的策略


    编辑2:你可能想看看史蒂文·德赫斯特(Steven Dewhurst)的书《C++Gotchas》(C++Gotchas)中的,特别是Gotcha 64和Gotcha 65。虽然它的重点是C++,但所涉及的课程在其他语言中是有用的。

    其他人可能需要纠正/澄清这一点,但有一种策略叫做(我相信)“契约驱动开发”,在这里您明确地在您的公共接口中记录了每个方法的预期的先决条件,以及保证的后条件。然后,在实现该方法时,任何阻止您满足合同中的post条件的错误都会导致抛出异常。未能满足先决条件被视为程序错误,应导致程序中止

    我不确定契约驱动的开发是否涉及捕获异常的问题,但一般来说,您应该只捕获您期望的并且可以合理地从中恢复的异常。例如,大多数代码无法从内存不足异常中进行有意义的恢复,因此捕获它没有意义。另一方面,如果您试图打开一个文件进行写入,您可以(而且应该)处理该文件被另一个进程以独占方式锁定的情况,或者该文件已被删除的情况(即使您在尝试打开它之前检查了它的存在)

    正如另一位评论者所指出的,您还应该避免使用异常来处理可以预期和避免的预期条件。例如,在.NET framework中,int.TryParse优于使用try/catch的int.Parse,尤其是在循环中使用时。

    异常不应用作对象内部方法之间内部传递信息的方法,而应在本地使用错误代码和防御编程

    异常被设计为将控制权从检测到错误的位置传递到可以处理错误的位置(堆栈的较高位置),这可能是因为本地代码没有足够的上下文来纠正问题,而堆栈的较高位置将有更多的上下文,从而能够更好地组织恢复

    当考虑异常时(至少在C++中),你应该考虑API的异常保证。最低保证水平应为基本保证,尽管您应努力(在适当情况下)提供强有力的保证。在不使用来自特定API的外部依赖项的情况下,您甚至可以尝试提供无抛出保证

    注意:不要混淆例外保证和例外规范

    例外保证: 不保证: 无法保证方法发生异常后对象的状态 在这些情况下,不应再使用该对象

    基本保证: 在几乎所有情况下,这应该是方法提供的最低保证。 这保证了对象的状态定义良好,并且仍然可以一致地使用

    强担保:(又名交易担保) 这保证了该方法将完全成功 或者将引发异常,并且对象状态不会更改

    无投掷保证: 该方法保证不允许任何异常传播出该方法。 所有析构函数都应提供此保证。
    |注意:当异常已经传播时,如果异常逃逸析构函数
    |申请将终止


    bea(现在的oracle)的这篇文章很好地阐述了如何做到这一点:。它有点像Java,但您也应该能够在其他环境中使用它。

    这篇来自微软高级软件设计工程师Eric Lippert的博客文章总结了一组优秀而简短的示例

    简言之:

    • 致命的:严重错误,表明您的流程完全无法恢复。尽可能清理所有资源,但不要抓住它们。如果您正在编写能够检测这种情况的代码,请务必抛出。示例:内存不足异常

    • bonehead:相对简单的错误,表明您的流程无法对所传递的任何数据进行操作,但会
      HRESULT Foo()
      {
          HRESULT hr = S_OK;
          try {
              // Avoid a whole lot of nested ifs and return code
              // checking - internal stuff just throws.
              DoStuff();
              DoMoreStuff(); // etc.
          } catch ( CAtlException& e ) {
              hr = e;
          }
          return hr;
      }
      
      void DoSomething()
      {
          // If something goes wrong, AtlThrow( E_FAILED or E_WHATEVER ); 
      }
      
      main 
      {
           try {
          all code....
          }
          catch(...) {} 
      }