.NET SqlConnection.Dispose()可以抛出异常吗?

时间:2014-12-15 16:52:27

标签: sql .net exception dispose unmanaged

Dispose对象的SqlConnnection方法是否可能抛出异常?它始终显示自己坐在try-catch外面的finally块中。如果使用块等同于try...finally,然后调用Dispose,那么Dispose引发的异常会出现问题似乎就是这种情况。

2 个答案:

答案 0 :(得分:5)

从技术上讲,可以,但不应该

CA1065: Do not raise exceptions in unexpected locations

  

IDisposable.Dispose方法不应抛出异常。 Dispose通常被称为finally子句中清理逻辑的一部分。因此,从Dispose显式抛出异常会强制用户在finally子句中添加异常处理。   Dispose(false)代码路径不应该抛出异常,因为这几乎总是从终结器调用。

Dispose Dos and Don'ts

  

不要在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中抛出异常可能有点邪恶,但在存在实际问题的情况下,仍然不会让它正常完成。