【问题标题】:Should my custom Exceptions Inherit an exception that is similar to them or just inherit from Exception?我的自定义异常应该继承与它们相似的异常还是只是从异常继承?
【发布时间】:2009-06-23 13:09:28
【问题描述】:

我正在我的应用程序中创建一些自定义异常。

如果我在测试参数状态后抛出异常,或者在测试 int 在适当范围内后抛出异常,我的异常应该继承 ArgumentException 和 IndexOutOfRangeException 还是应该继承例外?

【问题讨论】:

    标签: c# exception


    【解决方案1】:

    由于继承用于指定要捕获的异常,因此在做出决定时应首先尊重这一点。

    想想携带附加信息的 IOException,或 ArgumentOutOfRangeException 或 ArgumentNullException 以外的 ArgumentException。

    【讨论】:

      【解决方案2】:

      假设您确实需要自定义异常,我会从最符合您要求的异常继承,而不仅仅是从异常继承。

      也就是说,我发现在大多数情况下,在异常消息中使用正确的措辞通常足以创建一个全新的异常。

      例如,throw new IntOutOfProperRangeException();throw new ArgumentOutOfRangeException("The int value was too large?"); 有何显着不同

      【讨论】:

      • 有时需要(从外部)知道该 int 何时超出了适当的范围。你会怎么检查?我不认为一个好主意是询问抛出的异常是否是 ArgumentOutOfRangeException 异常以及消息是否等于“int 值太大?”。而不是那样,我认为这样做会更好:try {...} catch (IntOutOfProperRangeException ex) { //handle it }。当然,这取决于您的应用程序以及您需要用它做什么
      【解决方案3】:

      我认为创建一个新的异常类型总是更安全。如果您需要更改处理方式,则更容易找到您正在或可能正在处理它的案例。查找 MyException 比查找 ArgumentOutOfRangeException 的具体情况要容易得多。您似乎可以在异常中提供一些额外的信息,并且创建异常并没有太多工作。

      此外,我倾向于继承 MyBaseException 之类的基本应用程序类,并确保为异常添加 XML cmets。

      【讨论】:

      • +1 - 关于创建独特异常以帮助重构的绝妙之处。
      【解决方案4】:

      我只是好奇,你为什么不实际使用已经存在的异常?听起来这些异常正是您所需要的,您为什么反对使用它们?

      【讨论】:

      • 我正在测试更具体的东西,而不仅仅是泛型超出范围。例如,测试参数是否处于允许持久性的状态。在这种情况下,它正在检查一个参数,但我想要一个更具体的异常,称为 ArgumentNotInPersitableState 或类似的东西
      • 对于那种特殊情况,我会直接继承 Exception。
      • 您的调用者会捕捉到您的特定异常吗?如果没有,那么您不需要自己的异常类型。只需使用您自己的消息。
      【解决方案5】:

      就我个人而言,如果我有一个索引器并且索引值超出范围,那么我会简单地抛出现有的 IndexOutOfRangeException,我不会费心去继承它。

      如果您只讨论相似但不完全相同的异常,请查看框架中提供的模式。看起来这没有意义,继承描述了一种“is-a”关系。

      【讨论】:

      • 看看我对 BFree 的评论。在这种情况下,异常是 ArgumentException,但它更具体一些。
      • @Sruly:在这种情况下,我的第二段成立,不要这样做。从 ApplicationException 继承并完成它。
      【解决方案6】:

      如果您不需要向异常添加任何其他数据,那么我只需使用本机 .NET 异常,例如 IndexOutOfRangeException。

      但是,如果您需要将某些东西与您的异常相关联,而您不能使用 IndexOutOfRangeException 进行本机操作,那么我会继承它。这里的好处是您可以捕获新的自定义异常类型或 IndexOutOfRangeException。当然,如果你捕获了基类型,你就不会拥有额外的属性等。

      【讨论】:

      • 无论如何都不容易,您仍然可以进行类型检查并强制转换...(eww)
      • 是的,我没有提到它,因为如果我这样做了,我就得打自己。
      【解决方案7】:

      恕我直言,从另一个异常继承没有问题。它使该异常的目的更加清晰。但请确保适用于 ParentException 的所有内容也适用于您创建的 ChildException。否则,您最终可能会得到"Square extends Rectangle" problem...

      【讨论】:

      • 矩形不会扩展正方形吗?或者这就是重点?之前没遇到过这个词...
      • @Monoxide:不,Square 扩展了(Is-A)矩形。正如我的“所有正方形都是矩形。并非所有矩形都是正方形”
      • 刚刚添加了一个链接来指出“方形扩展矩形”问题
      【解决方案8】:

      我几乎总是将 IllegalArgumentException(空值和/或超出范围的值)和 IllegalStateException 用于不比 IOException、SQLException、Null 更具体的任何事情......

      【讨论】:

        【解决方案9】:

        我认为这完全取决于您是否要将 ArgumentNotInPersitableState 异常捕获为 ArgumentOutOfRange。如果会有这样的 catch 块(或者如果您正在编写一个框架,可能会被其他人使用)那么是的,您应该继承相关的异常类型。

        【讨论】:

          【解决方案10】:

          如果您只使用通用异常,您将永远无法捕获为您的应用程序自定义的特定异常。如果你只是使用

          try 
          {
          }
          catch (Exception ex)
          {
          }
          

          您将捕获每个异常,但无法过滤特定错误。

          我创建自定义异常的另一个原因是处理可能由于多种原因而发生的特定于应用程序的异常。这允许意味着抛出自定义异常但自定义与异常关联的消息。它还为我的特定应用程序提供了另一个级别的错误处理。

          例如,我有一个工程应用程序,用于确定皮带传动系统的大小。该 dll 也可供其他人使用。 I have an application exception that is thrown when an error occurs in the selection.错误的原因可能有很多(无效的驱动速度、不正确的马力要求等)。由于失败的原因有很多,自定义应用程序异常允许我提供失败的具体细节。

          这还允许我向用户记录方法调用将引发他们需要处理的应用程序特定异常。

          如果您继承的 Exception 类,请确保在基类中实现具有消息、消息 + 内部异常和序列化异常的构造函数。

          这是我的一个例子。

          /// <summary>
          /// Drive error exception class. Thrown when a drive selection error has occured.
          /// </summary>
          [Serializable]
          public class DriveException : SystemException
          {
              /// <summary>
              /// Default constructor.
              /// </summary>
              public DriveException()
              {
              }
              /// <summary>
              /// Constructor used with a message.
              /// </summary>
              /// <param name="message">String message of exception.</param>
              public DriveException(string message)
                  : base(message)
              {
              }
              /// <summary>
              /// Constructor used with a message and an inner exception.
              /// </summary>
              /// <param name="message">String message of exception.</param>
              /// <param name="inner">Reference to inner exception.</param>
              public DriveException(string message, Exception inner)
                  : base(message, inner)
              {
              }
              /// <summary>
              /// Constructor used in serializing the data.
              /// </summary>
              /// <param name="info">Data stored to serialize/de-serialize</param>
              /// <param name="context">Defines the source/destinantion of the straeam.</param>
              public DriveException(SerializationInfo info, StreamingContext context)
                  : base(info, context)
              {
              }
          }
          

          【讨论】:

          • 你不应该从ApplicationException (source)继承。
          猜你喜欢
          • 2015-10-14
          • 2016-03-20
          • 1970-01-01
          • 1970-01-01
          • 2012-03-12
          • 2012-07-14
          • 2020-10-16
          • 1970-01-01
          • 2019-02-21
          相关资源
          最近更新 更多