【问题标题】:How do I chose the most appropriate type of exception to throw?如何选择最合适的异常类型来抛出?
【发布时间】:2009-05-27 12:38:20
【问题描述】:

已经有很多关于例外的问题,但我找不到能回答我的问题的问题。如果我错过了另一个问题,请随时指出我的方向。

我的问题很简单:其他 (C#) 开发人员如何选择最合适的异常类型来抛出?之前我写了以下代码:

    if (Enum.IsDefined(enumType, value))
    {
        return (T)Enum.Parse(enumType, value);
    }
    else
    {
        throw new ArgumentException(string.Format("Parameter for value \"{0}\" is not defined in {1}", value, enumType));
    }

我后来意识到,如果我当时知道它的存在,那么抛出 InvalidEnumArgumentException 可能会更合适。

是否有可用的权威资源来帮助开发人员选择异常类型,或者仅仅是经验问题?

编辑

我已经给诺多林积分,因为它在一个深思熟虑的答案中提供了一系列想法。积分可能真的属于你们中的任何人 - 感谢所有建议。

【问题讨论】:

    标签: c# exception


    【解决方案1】:

    Krzysztof Cwalina 在此 see chapter "1.1.1 Choosing the Right Type of Exception to Throw" 上有一个很好的帖子

    PS 考虑订阅他的博客。好好读书!

    回答您的问题:InvalidEnumArgumentException
    因为抛出最具体(最衍生的)有意义的异常。

    捕获 ArgumentException 的调用者也捕获 InvalidEnumArgumentException...

    【讨论】:

    • 和捕获 ArgumentException 的调用者,也捕获 InvalidEnumArgumentException...
    【解决方案2】:

    我会说这取决于经验。我仍然经常发现新的异常,而且我已经使用 .NET 的许多方面工作了一段时间!无论如何,您希望此消息来源告诉您什么?选择适当的异常类型似乎是高度特定于上下文的,所以我怀疑它可以提供的建议水平。列出更常见的将是它所能提供的最多的。异常类型的名称和 Intellisense 描述通常清楚地解释了它们的使用场景。

    我的建议是让自己熟悉所有基础知识(特别是 SystemSystem.IO 以及您经常使用的任何其他名称空间中的那些),并在此过程中学习其他名称。我发现我通常只使用一小部分就可以逃脱。如果您在 BCL 中已经存在更具体的异常类型时意外使用了更通用的异常类型,那么这不是什么大罪,并且可以在以后轻松更改。老实说,对于任何特别具体的错误,您通常都需要创建自己的类来继承 Exception

    希望对您有所帮助。

    编辑:如果您想了解非常常见的简要指南,请参阅 MSDN 上的 Common Exception Classes 页面。

    【讨论】:

    • 太好了,感谢您的建议。我已经编写 C# 5 年左右了,并且经常想知道我是否遗漏了一些东西。知道这真的只是经验问题,这让人放心:)
    • @thedorko:没问题...是的,只要您知道重要的(可能不超过十几个),就没有什么可担心的。
    • 上面的 Common Exceptions Classes 链接坏了,here 是另一个。
    【解决方案3】:

    Common Exception Types and their Explanations

    我认为这可能会帮助您找出最适合您使用的例外情况。如果需要,您还可以查看 MSDN 文档以获取有关 Exception 类及其所有类型的更多信息。

    【讨论】:

    • 嗯,那篇文章远非详尽无遗。在那篇文章出现之前,开发人员做了什么?我正在寻找权威资源,谢谢。
    • thedorko:MSDN 文档(我现在提供了一些链接)将为您提供更全面的异常类型列表。但正如后来的海报所说,其中很多确实归结为经验和老式直觉的结合。正如 Grzenio 在下面发布的那样,开发人员定义的异常类也没有什么坏处,尽管花在创建所需的所有特定异常类型上的时间最终可能不值得。
    • 抱歉,不是简短的意思。正如你所说,“经验和老式直觉的结合”似乎是答案——这很好。我觉得我错过了一些东西,因为我一直在使用直觉,但是当我发现我可以使用的更合适的类型时仍然觉得很烦人。正如 Jamie Ide 指出的那样,除非您打算以不同的方式处理每种类型,否则无论如何都不必担心抛出特定的异常类型。
    • 正确。如果你专注于显而易见的事情,你会很安全。如果您必须强迫自己在档案中挖掘有关深奥且很少使用的异常类型的定义,那么您最好使用更常见的(即使它不一定是最合适的)或创建你自己的(至少你会知道它的用途)。
    【解决方案4】:

    如果您查看MSDN article on System.Exception,页面底部是继承 Exception 的 BCL 异常类型的完整列表。它不是一个关于什么应该用于什么的明确列表 - 但它确实为您提供了一个开始检查异常类型的好地方。浏览每个将告诉您它们应该用于什么:

    还有一篇关于 .NET 异常层次结构的相当全面的文章,位于:

    事实上,MSDN 库中关于处理和抛出异常的整个部分都非常好:

    【讨论】:

      【解决方案5】:

      我将大多数常见的例外情况写在我办公桌上的明信片上,当人们尝试以一种特殊的方式与我互动时使用它们。

      这对于找出最适合的异常是非常好的做法...

      我发现自己最常使用的是 OperationNotSupportedException

      【讨论】:

      • 你会把明信片扔给他们吗?
      【解决方案6】:

      我认为真正的问题是问自己“我要处理哪种类型的异常?”如果您不打算对 InvalidEnumArgumentException 或 ArgumentException 进行特殊处理,那么与普通的旧异常相比,它们没有任何优势。

      我通常要么抛出异常,要么将异常包装在自定义异常中。

      编辑添加: 有一次,我记得微软的指导是你的应用程序永远不应该抛出框架异常,而应该只抛出 ApplicationException 的扩展。

      【讨论】:

      • 由于 InvalidEnumArgumentException 继承自 ArgumentException,因此捕获 ArgumentException 可以同时捕获...
      【解决方案7】:

      我通常定义自己的异常结构,首先创建一些基础异常:

      class MyProjectNameException:Exception
      {
      ...constructors, etc
      }
      

      然后派生类以获得更精确的异常。通过这种方式,您可以准确地知道什么时候会出现哪个异常,并且您可以知道异常是由您还是由框架引发的。

      【讨论】:

      • 好提示,谢谢。你不会考虑抛出其中一种标准异常类型吗?
      • 创建新的异常类型不是一个好习惯,只是为了让您自己的团队有异常
      • +1,我同意。来自 Java 背景,这就是我一直做的事情,尽管我觉得我在 C# 中使用异常的次数比在 Java 中少得多,因为缺少检查的异常(Java 世界中我真的很怀念这一点)。
      【解决方案8】:

      如果你找到一个合适的例外,你可以使用它。

      如有疑问,请使用ApplicationException。这是针对不属于标准库的代码的异常。

      如果不打算以标准化方式使用异常(例如捕获基类IOException 以捕获任何与 I/O 相关的错误),则您放入异常中的消息比类型更有用例外。

      【讨论】:

      • msdn.microsoft.com/en-us/library/ms229007%28v=vs.110%29.aspx 怎么会说“不要抛出或派生自 ApplicationException”?
      • @wisbucky:因为您正在阅读最新框架版本的文档。在最早的版本中,建议使用ApplicationException,但随着版本逐渐转向相反的方向。假设您正在阅读五年前的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      • 2021-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多