读过线程Is SqlCommand.Dispose enough?和Closing and Disposing a WCF Service我想知道SqlConnection等类或继承自Stream类的几个类之一是否关闭Dispose而不是Close?
答案 0 :(得分:173)
根据Microsoft指南,在合适的情况下提供Close
方法是一种很好的做法。 Here是来自Framework design guidelines
如果close是该区域的标准术语,请考虑提供方法
相同Close()
以及Dispose()
。执行此操作时,务必使Close
实施与Dispose
...
在大多数情况下,Close
和Dispose
方法是等效的。在Close
的情况下,Dispose
和SqlConnectionObject
之间的主要差异是:
应用程序可以再调用
Close
不止一次。没有例外 生成。如果您调用
Dispose
方法SqlConnection
对象状态将是 重启。如果你试图打电话给任何人 处置SqlConnection
的方法 对象,你将收到异常。
那说:
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();
}
}