【发布时间】:2012-02-21 13:41:08
【问题描述】:
我经常发现自己处于必须处理接口实现者抛出的一些异常的情况。当不同的实现处理完全不同类型的设备等时,这通常会出现问题:根据实现的不同,抛出的异常的数量和类型会有很大差异。这是一个典型的例子:
interface DataStream
{
Data ReadNext();
}
class DeserializingFileDataStream : DataStream
{
//this one does file operations + serialization,
//so can throw eg IOException, SerializationException, InvalidOperationException, ...
}
class NetworkDataStream : DataStream
{
//get data over tcp
//so throws IOException, SocketException
}
class HardwareDeviceDataStream : DataStream
{
//read from a custom hardware device implemented in unmanaged code
//so throws mainly custom exceptions
}
可能所有这些也会抛出 ArgumentExceptions 等等,但我对捕捉这些不感兴趣:在这种情况下,它们将指示编程错误。但是我不希望程序在文件损坏、网线拔出或自定义设备失控时崩溃,所以应该处理其他异常。
我已经尝试了几个解决方案,但没有一个是我特别满意的,所以问题是:是否有一些常见的做法/模式来处理此类情况?请具体一点,不要告诉我“看看 ELMAH”。以下是我过去使用的一些东西:
-
catch( Exception )嗯,问题很明显 -
TryAndCatchDataStream( Action what, Action<Exception> errHandler )方法由一个 try 和一个 catch 组成,用于任何实现中感兴趣的任何异常。这意味着它必须在实现更改或添加/删除时进行更新。 - 在接口上添加注释说“应该只抛出 DataStreamExceptions”,并且在所有实现中确保遵循此规则,捕获任何感兴趣的内容并将其包装在 DataStreamException 中,然后将其抛出。还不错,但会给每个实现增加噪音。
然后我有第二个关于异常处理的更一般的问题(认为不需要为此单独发帖):我有一些情况,方法 A 调用 B,它调用 C 调用 D,而 D 抛出一个SomeException 但 A 的调用者捕获了异常。这不是代码有问题的迹象吗?因为要做到这一点,A 的调用者需要知道 A 最终会调用 D。除非 A 记录它可以抛出 SomeException;但在这两种情况下,这意味着当更新 A 的单纯实现细节时(即让它调用 D 以外的其他东西),此更改对 A 的用户是可见的。
【问题讨论】:
-
我会选择第三个选项。对于你的第二个问题,我认为这不是问题,只要它被评论它可以抛出那个异常。怎么能扔? 封装!
-
这无关紧要,因为您应该只捕获您知道如何处理的异常。如果你连异常是什么都不知道,那么你显然无法处理它。
标签: c# exception-handling error-handling