【问题标题】:Can a custom stream throw its own custom exceptions or should it only throw IOException?自定义流可以抛出自己的自定义异常还是应该只抛出 IOException?
【发布时间】:2013-02-08 22:45:12
【问题描述】:

我有自己的 Connection 类和 ConnectionStream 类,它基本上只是包装了 Connection 的发送/接收方法。

Connection 发送/接收方法可以抛出异常,例如 ServerClosedConnException 或 NetworkShutdownException

我的 Stream 是否应该捕获这些并将它们包装在 IOException 中(使用 innerException),或者它可以让它们冒泡给用户(当然还有一些 try-finally 来处理清理)

我在 .NET 框架中看到,NetworkStream 将来自 Socket 的任何错误包装在一个 IOException 中

【问题讨论】:

  • 没有。 .NET Stream 派生类不这样做。

标签: c# exception-handling stream


【解决方案1】:

除非您打算处理异常,否则不要捕获异常。它们将在调用堆栈中冒泡,直到上游处理程序捕获并处理它们,或者程序终止。

如果您的 Connection 类抛出了一个非常具体的异常,例如 ServerClosedConnExceptionNetworkShutdownException,而您抓住了它并重新抛出了一个不太具体的 IOException,我不明白这是怎么回事添加任何值。

【讨论】:

  • 谢谢。但是,当读取/写入调用失败时,为什么 .NET NetworkStream 类会将 SocketExceptions 包装在 IOException 中?
  • 嗯,也许它确实抛出了 SocketException,出于某种原因,我记得它包装了异常。我现在就测试一下。
  • 可能是因为通过重新抛出,它们不会暴露底层类的实现细节。
  • 这就是我所关心的。我希望我的流与 NetworkStream 一样可重用。我不知道我是不是傻。
  • 我刚刚测试了 NetworkStream 类,它确实将 SocketExceptions 包装在 IOException 中。
【解决方案2】:

Stream 基类充当其子类的事实上的契约。如果您计划在公共 API 中公开您的子类,最好遵守 Stream 类的记录行为,因为您的子类的用户可能不知道它的特定类型。例如,如果您希望遵守 Read 方法的约定,则您的实现不应公开任何不属于http://msdn.microsoft.com/en-us/library/system.io.stream.read 中列出的类型的异常。

但是,这并不意味着您不能使用更具体的异常类型。如果您有理由无论如何都要创建自定义异常类型(假设您在阅读了 JerKimball 提到的design guidelines 后认为这是一个好主意),它可能是 IOException 的子类。但是,这可能不是必需的,除非您的 Stream 子类的用户除了记录异常详细信息之外可能还想做其他事情。

【讨论】:

  • System.Net.Sockets.NetworkStream 类包装了在 IOException 中发生的任何 SocketException。除了你所说的关于事实上的合同之外,似乎没有任何理由。你认为我的目标是让我的 ConnectionStream 类和 NetworkStream 类一样可重用吗?还是只是我很迂腐?
  • 这取决于谁将使用您的子类。如果它是将在您的直接工作组之外使用的公共 API 的一部分,那么符合 Stream 的预期合同将是“礼貌的”。想象自己是一名开发人员,正在使用类型为 Stream 并通过依赖注入提供的子类实例:您希望该类如何处理与连接相关的异常?
  • 这个答案非常有帮助,谢谢。我决定让我的 Stream 抛出连接异常。
【解决方案3】:

最佳做法是让异常冒泡除非您有更多细节要添加您可以自己处理异常。在第一种情况下,您抛出一个新异常,实际异常为InnerException

阅读 MSDN 中的Wrapping Exceptions

在你的情况下,我会让它冒泡。

【讨论】:

    【解决方案4】:

    以下是例外指南的内容:

    [参考]

    最相关的部分:

    Do throw the most specific (the most derived) exception that is appropriate. 
    For example, if a method receives a null (Nothing in Visual Basic) argument, 
    it should throw System.ArgumentNullException instead of its base type 
    System.ArgumentException.
    

    我会推断这也意味着在您的情况下,最详细的例外是要传播的“正确”例外;对您的异常类型进行一些假设,它们可能是要传播的“正确”类型,可能包装在“ConnectionException”自定义异常中。

    也就是说,我确实看到考虑将其包装在 IOException 中“有意义”,因为这是异常的“形状”;但是如果我不同意这些指导方针并且我按照自己的方式行事,它通常会在以后的路上咬我。 :)

    【讨论】:

      猜你喜欢
      • 2011-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-03
      • 1970-01-01
      • 2011-05-30
      相关资源
      最近更新 更多