Dispose
对象的SqlConnnection
方法是否可能抛出异常?它始终显示自己坐在try-catch外面的finally块中。如果使用块等同于try...finally
,然后调用Dispose
,那么Dispose
引发的异常会出现问题似乎就是这种情况。
答案 0 :(得分:5)
从技术上讲,可以,但不应该:
CA1065: Do not raise exceptions in unexpected locations:
IDisposable.Dispose
方法不应抛出异常。Dispose
通常被称为finally子句中清理逻辑的一部分。因此,从Dispose
显式抛出异常会强制用户在finally子句中添加异常处理。Dispose(false)
代码路径不应该抛出异常,因为这几乎总是从终结器调用。
不要在Dispose中抛出异常。调用Dispose的对象没有任何问题。
故事的寓意似乎是Dispose
抛出的异常是一件非常糟糕的事情(由于你提到的一些原因),应该尽可能高地处理(没有什么)你可以做些什么,也许无法从中恢复过来。
答案 1 :(得分:1)
通常,如果系统的状态与周围代码所期望的相匹配,则代码块应该正常完成,如果它不胜,则抛出异常。然而,.NET中的try / catch / finally结构有一个弱点,它流入IDisposable
接口,该接口设计用于它(通过像using
这样的语言结构):一个方法
void Test()
{
try
{
doSomething();
}
finally
{
doCleanup();
}
}
只有 doSomething()
和doCleanup()
成功时才会正常退出,但如果doSomething()
抛出异常,则Test()
方法作为一个整体应该抛出该异常还是可以记录它。满足这两个要求要求doCleanup()
在成功调用doSomething()
之后抛出异常,但不要跟随引发异常的调用,否则抛出的任何异常都会包含有关该异常的信息。从doSomething()
抛出的异常。
不幸的是,没有方便的方法来编写finally
块来根据try
的结果改变其行为,也没有任何方法可以调用Dispose()
方法一个finally
这样做。因此,Dispose
实现有必要尝试猜测在操作失败时是否更加邪恶退出,或者抛出可能覆盖包含有用信息的早期异常的异常。后者有点邪恶,但往往不像前者那样邪恶。
例如,考虑伪代码:
RenameFile(mainFileName, backupFileName);
using(outFile = File.Create(mainFileName);
{
writeDataToNewFile(outFile);
}
DeleteFile(backupFileName);
如果在关闭输出文件时出现问题并且异常从using
块传播出来,则备份文件将保持不变并可能在以后恢复。如果允许using
块正常完成,尽管失败导致主文件无法正确写入,则备份文件将被删除,可能会破坏其中包含的某些数据的唯一副本。
Dispose
不应该抛出异常的想法与以下事实有关:通常没有好办法处理从Dispose
抛出的异常。然而,更大的问题是,Dispose
期间出现的问题没有好的方法,而不知道调用它的情况。从Dispose
中抛出异常可能有点邪恶,但在存在实际问题的情况下,仍然不会让它正常完成。