【问题标题】:Exception handling: user defined exception benefits异常处理:用户定义的异常好处
【发布时间】:2011-07-16 13:50:38
【问题描述】:

我的异常处理技能非常初级,我总是对应该使用它们的方式感到非常困惑,而不是如何/语法。我目前正在使用 C#(如果有不同的适用于它的话)。

我的问题是,在开发应用程序时创建自己的异常类有什么好处?与抛出标准 Exception 类异常相比。基本上,在您的应用程序中,什么是健康的异常做法。

如果没有好处,那就是坏处?

【问题讨论】:

  • 我已经投票了所有对我有帮助的答案,并且因为有很多(谢谢)我发现对我有益,所以我决定投票而不是选择一个答案。

标签: c# c#-4.0 programming-languages exception-handling


【解决方案1】:

通过创建自己的异常,您通常可以为最终用户创建更有意义的消息(或更多特定于应用程序的消息类型),同时仍然包装原始消息,以免丢失任何有用的信息。

有一个很棒的 book by Bill Wagner 涵盖了一些关于何时应该或不应该创建自己的异常的推理以及一般异常处理的一些良好实践。以下是一小段摘录:

您的应用程序会抛出异常——希望不会经常发生,但它 会发生。如果您不做任何特定的事情,您的应用程序将 每当出现问题时生成默认的 .NET Framework 异常 您在核心框架上调用的方法有误。提供更多 详细信息将对您和您的用户大有帮助 诊断并可能纠正该领域的错误。你创造 不同纠正措施时的不同异常类别 可能且仅当可能采取不同的行动时。你创造 通过提供所有构造函数来提供功能齐全的异常类 基础异常类支持。您使用 InnerException 属性 携带下层产生的所有错误信息 错误条件。

【讨论】:

  • 感谢本书参考!
  • @nEm:没问题。伟大的阅读。他还出版了另一本名为《更有效的 C#:50 种改进 C# 的特定方法》的书,这本书同样出色。 amazon.com/More-Effective-Specific-Ways-Improve/dp/0321485890
  • 哦,太好了!再次非常感谢。我会检查他们。没有健康的编码习惯,语言知识毫无用处。
【解决方案2】:

如果您的应用程序存在特定类型的问题,需要在更高级别的应用程序中采用独特的恢复策略,您应该创建自己的异常类型,以便以最佳方式识别此类问题并从中恢复.

如果错误更像是“调用者做错了什么”,请使用标准异常类。

如果您认为您的库将长期存在且有价值,那么我会犯错误的是创建您自己的异常类,以便您的库的未来用户可以制定自己的恢复策略。

【讨论】:

    【解决方案3】:

    有时您想针对不同类型的错误执行不同的操作,例如,如果用户输入了错误的数据,则不会导致整个应用程序崩溃并向管理员发送电子邮件。对于更严重的异常(例如堆栈溢出),这样做是有意义的。然后,您将根据错误类型实施不同的捕获。

    【讨论】:

    • 这是因为抛出一个“异常”异常,因为它是通用的,所以可以在任何地方捕获?
    • 错误的用户输入不应引发异常。例外是针对特殊情况,而用户输入的数据不正确。
    • Sjoerd:理想情况下是的,但有时用户输入会通过您的验证
    • 哦,我并不是说只针对糟糕的用户输入,我是在抛出异常的情况下说的,因为我需要。
    • 是的,我同意 Tom Squires 的观点,有时您可能会忘记检查验证方法的布尔结果,用户输入没有例外
    【解决方案4】:

    如果一个方法被记录为在某些特定情况下抛出某个特定类的异常,它应该确保在其他情况下该类的任何异常都不会通过它冒泡。在许多情况下,确保这一点的最实用方法可能是创建自定义异常类。

    实际上,我认为大部分异常层次结构毫无用处,并建议关注相当少数的异常,几乎所有好的异常都应从中派生。

    1. CleanFailureException -- 由于某种原因无法执行指示的操作,但未更改任何对象的状态。没有理由相信任何对象的状态是损坏的,除非操作失败所暗示的程度。如果 TrySomething 方法返回 False,这应该是 DoSomething 方法抛出的异常类型。如果失败的操作使一个或多个对象处于部分更改或不一致的状态,则在某些情况下可能会包含在更严格的指令中。
    2. StateDisturbedException -- 指示的操作由于某种原因无法完全执行,但可能已部分执行。正在对其执行操作的对象具有符合其自身不变量的状态,但可能符合也可能不符合调用者对它的期望。只有在检查对象并确保它符合预期(根据需要更改它)之后,调用者才可能尝试使用该对象。或者,应在目标对象不再存在的位置捕获此异常,然后将其包装在 CleanFailureException 中。
    3. TargetStateCorruptException - 指示的操作无法执行,因为正在执行的特定对象已损坏,但没有特别的理由可以预期损坏会扩展到对象之外。应该在目标对象不再存在的地方捕获此异常,然后用 CleanFailureException 进行包装和替换。
    4. ParentStateCorruptException -- 指示的操作无法执行,因为目标文档认为是“父”对象的某些对象已损坏。捕获损坏的父对象不再存在的级别,然后包装在“CleanFailureException”中。
    5. SystemOnFireException

    虽然用异常名称来指示问题的性质可能会很好,但从捕捉的角度来看,重要的是是否可以安全地捕捉和恢复。任何异常层次结构都应该关注后者,而不是前者。如果目标是通知人们出了什么问题,那应该在 Exception.Message 中完成。

    【讨论】:

      【解决方案5】:

      主要好处是添加信息,因此异常更有意义,因此允许捕获特定于您的应用程序的异常。

      【讨论】:

        【解决方案6】:

        抛出异常实际上是一个比悄悄失败更昂贵的操作,比如返回一个布尔值。这个问题突出了我的意思:

        How much more expensive is an Exception than a return value?

        如果您正在编写一些您预计其他开发人员将在他们自己的项目中使用的东西,那么可以肯定的是,异常可能对他们有用,以确保他们正确使用您的代码。否则,如果您只是在自己的代码库中使用它,我会确保悄悄地失败。

        【讨论】:

          【解决方案7】:

          自定义异常运行良好的一个例子是当您期望外部应用程序与您的项目交互时。

          例如,如果您有一个发送电子邮件的小型项目,如果您对必须通过电子邮件发送的最少收件人数量有硬性限制,那么引发自定义“TooFewRecipients”错误可能是有意义的。

          自定义异常通常继承自 System.Exception

          请记住,异常只能用于您的项目无法以任何其他方式处理的异常情况,并且它们应该易于理解,以帮助第 3 方开发人员理解问题。更多信息MSDN

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-09-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-11
            • 2015-07-01
            相关资源
            最近更新 更多