关闭和处理 - 要打电话?

时间:2008-09-14 03:17:32

标签: .net

读过线程Is SqlCommand.Dispose enough?Closing and Disposing a WCF Service我想知道SqlConnection等类或继承自Stream类的几个类之一是否关闭Dispose而不是Close?

7 个答案:

答案 0 :(得分:173)

我想澄清一下这种情况。

根据Microsoft指南,在合适的情况下提供Close方法是一种很好的做法。 Here是来自Framework design guidelines

的引文
  

如果close是该区域的标准术语,请考虑提供方法Close()以及Dispose()。执行此操作时,务必使Close实施与Dispose ...

相同

在大多数情况下,CloseDispose方法是等效的。在Close的情况下,DisposeSqlConnectionObject之间的主要差异是:

  

应用程序可以再调用Close   不止一次。没有例外   生成。

     

如果您调用Dispose方法   SqlConnection对象状态将是   重启。如果你试图打电话给任何人   处置SqlConnection的方法   对象,你将收到异常。

那说:

  • 如果您使用连接对象1 时间,请使用Dispose
  • 如果必须重复使用连接对象, 使用Close方法。

答案 1 :(得分:23)

通常答案是:这取决于。不同的类以不同的方式实现IDisposable,由你来做必要的研究。

SqlClient而言,建议的做法是执行以下操作:

using (SqlConnection conn = /* Create new instance using your favorite method */)
{
    conn.Open();
    using (SqlCommand command = /* Create new instance using your favorite method */)
    {
        // Do work
    }
    conn.Close(); // Optional
}

应该在连接上调用Dispose(或Close *)! 等待垃圾收集器清理连接,这将占用池中的连接,直到下一个GC周期(至少)。如果您致电Dispose,则无需拨打Close,因为using结构可以很容易地正确处理Dispose,所以没有理由打电话Close

自动池化连接,并且在连接上调用Dispose / Close不会物理关闭连接(在正常情况下)。不要尝试实现自己的池。 SqlClient在从池中检索连接时对连接执行清理(如恢复数据库上下文和连接选项)。

*如果您正在调用Close,请确保以异常安全的方式(即在catch或finally块中)执行此操作。

答案 2 :(得分:11)

您需要调用Dispose()!

Dispose()供开发人员调用,垃圾收集器调用Finalize()。如果你没有在你的对象上调用Dispose(),那么他们使用的任何非托管资源都不会被丢弃,直到垃圾收集器出现并调用它们(并且知道何时会发生)。

此方案称为非确定性终结,是.net开发人员的常见陷阱。如果您正在使用实现IDisposable的对象,请在它们上调用Dispose()!

http://www.ondotnet.com/pub/a/oreilly/dotnet/news/programmingCsharp_0801.html?page=last

虽然可能有很多实例(比如在SqlConnection上),你在某个对象上调用Disponse(),它只是在它的连接上调用Close()或关闭文件句柄,它几乎总是你最好的选择Dispose()方法!除非您打算在不久的将来重新使用该对象。

答案 3 :(得分:10)

对于SqlConnection,从连接本身的角度来看,它们是等价的。根据Reflector,Dispose()调用Close()以及执行一些额外的内存释放操作 - 主要是通过将成员设置为null。

对于Stream,它们实际上是等价的。 Stream.Dispose()只需调用Close()。

答案 4 :(得分:6)

这个快速的建议成了一个很长的答案。遗憾。

正如泰勒在他的回答中指出的那样,调用Dispose()是一种很棒的编程习惯。这是因为这种方法应该“集合”所需的所有资源释放,因此没有不需要的开放资源。例如,如果你在文件中写了一些文本,并且无法关闭文件(释放资源),那么它将保持打开状态,并且没有其他人能够写入它,直到GC出现并执行你应该拥有的内容完成。

现在,在某些情况下,会有更新特定于您正在处理的类的“最终化”方法,例如StreamWriter.Close(),它会覆盖TextWriter.Close()。实际上它们通常更适合这种情况:例如,StreamWriter的Close()Dispose()对象之前刷新流和底层编码器!酷!

然而,浏览MSDN你会发现即使微软有时会被众多的关闭器和处理器所困惑。例如,In this webpage在某些示例中Close()在隐式Dispose()之前被调用(如果您不理解为什么它是隐含的,请参阅using statement),尤其是他们不打扰。那为什么会这样?我也很困惑。

我想的原因(并且,我强调,这是original research,如果我错了,我肯定可能会失去声誉)是 Close()可能会失败,在离开时会产生异常资源是开放的,而Dispose()肯定会释放它们。这就是为什么 Dispose()应始终保护Close()来电(对不起双关语)。

MyResource r = new MyResource();

try {
  r.Write(new Whatever());

  r.Close()
finally {
  r.Dispose();
}

是的,我猜微软在这个例子上滑倒了。也许那个时间戳永远不会被刷新到文件中。

明天我正在修复旧代码。

编辑:抱歉Brannon,我无法对你的回答发表评论,但你确定在Close()块上拨打finally是个好主意吗?我猜这个例外可能会破坏块的其余部分,这可能包含重要的清理代码。

回复Brannon's:很好,只是在真正需要时不要忘记调用Close()(例如在处理流时 - 不太了解.NET中的SQL连接)。 / em>的

答案 5 :(得分:2)

对iDisposable进行类型转换,然后调用处理。这将调用配置为实现“iDisposable.Dispose”的任何方法,无论该函数的名称是什么。

答案 6 :(得分:2)

一般来说,我们在Close(),Abort()和Dispose()中遇到问题,但是让我告诉你它们之间的区别。

1)ABORT: - 我不建议使用它,因为当调用abort时,客户端将删除连接而不告诉服务器,因此服务器将等待一段时间(大约1分钟)。如果您有批量请求,那么您无法使用abort(),因为它可能会导致您的有限连接池超时。

2)关闭: - 关闭是关闭连接的非常好的方法,因为当关闭连接时,它将调用服务器并确认服务器也将被关闭。

在这里,还有一件事要看。 在某些情况下,如果生成错误,那么最终在connection.close()中编写代码并不是一种好方法,因为此时通信状态将出现故障。

3)处理: - 这是一种关闭类型,但在关闭连接后,您无法再次打开它。

所以试试这个,

private void CloseConnection(Client client)
    {
        if (client != null && client.State == CommunicationState.Opened)
        {
            client.Close();
        }
        else
        {
            client.Abort();
        }
    }