closures和处置 – 要调用哪个?
读过线程SqlCommand.Dispose是否足够? 和closures和处置一个WCF服务我想知道类如SqlConnection或从Stream类inheritance的几个类之一,如果我closuresDispose而不是closures它是否重要?
我想澄清这种情况。
根据Microsoft的指导方针,在合适的地方提供Close
方法是一个很好的做法。 以下是框架devise指南的引用
考虑提供方法
Close()
,除了Dispose()
,如果close是该领域的标准术语。 这样做时,将“Close
实现与“Dispose
Close
相同是非常重要的。
在大多数情况下, Close
和Dispose
方法是等价的。 在SqlConnectionObject
的情况下Close
和Dispose
的主要区别是:
应用程序可以多次调用
Close
。 没有exception产生。如果你调用
Dispose
方法,SqlConnection
对象的状态将被重置。 如果您尝试调用处置SqlConnection
对象的任何方法,您将会收到exception。
那就是说:
- 如果一次使用连接对象,请使用
Dispose
。 - 如果连接对象必须重用,请使用
Close
方法。
像往常一样,答案是:这取决于。 不同的类以不同的方式实现IDisposable
,这取决于你做必要的研究。
就SqlClient
而言,build议的做法是执行以下操作:
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周期(至less)。 如果调用Dispose
,则不需要调用Close
,并且由于using
构造使正确处理Dispose
变得非常容易,所以实际上没有理由调用Close
。
连接会自动合并,并在连接上调用Dispose
/ Close
不会在物理上closures连接(正常情况下)。 不要试图实现自己的池。 SqlClient
从连接池中检索连接时执行清理(如恢复数据库上下文和连接选项)。
*如果您调用Close
,请确保以exception安全的方式执行(即在catch或finally块中)。
你需要调用Dispose()!
垃圾收集器调用Finalize()来调用Dispose()。 如果不在对象上调用Dispose(),那么他们使用的任何非托pipe资源都将不会被处理,直到垃圾收集器出现并调用finalize(谁知道什么时候会发生)。
这种情况被称为非确定性终结,是.net开发人员的常见陷阱。 如果您正在使用实现IDisposable的对象,请调用Dispose()!
http://www.ondotnet.com/pub/a/oreilly/dotnet/news/programmingCsharp_0801.html?page=last
虽然可能有很多实例(如SqlConnection),在某些对象上调用Disponse(),并且只是在连接上调用Close()或closures文件句柄, 但调用Dispose()几乎总是最好的select! 除非你计划在不久的将来重用这个对象。
对于SqlConnection
,从连接本身来看,它们是等价的。 根据Reflector, Dispose()
调用Close()
以及执行一些额外的内存释放操作 – 主要是通过将成员设置为null。
对于Stream来说,它们实际上是等效的。 Stream.Dispose()
只是调用Close()。
这将是快速的build议成为一个长期的答案。 抱歉。
正如泰勒在他的不错的答案中指出的,调用Dispose()
是一个伟大的编程实践。 这是因为这种方法应该“团结起来”,所有的资源释放需要,所以没有不必要的开放资源。 例如,如果你为文件写了一些文本,并且没有closures文件(释放资源),它将保持打开状态,在GC出现之前,没有其他人能够写入文件,并且做你应该做的事情完成。
现在,在某些情况下,会有更多特定于您正在处理的类的“完成”方法,如重写TextWriter.Close()
StreamWriter.Close()
TextWriter.Close()
。 事实上,它们通常更适合这种情况:例如,StreamWriter的Close()
在Dispose()
之前刷新stream和底层编码器! 凉!
然而,浏览MSDN,你会发现,即使微软有时也被大量的closures和处置者所困惑。 例如, 在这个网页中 ,在一些例子中,在隐式Dispose()
之前调用了Close()
(如果你不明白为什么它是隐含的,请参阅using语句 ),特别是他们不打扰。 为什么会这样? 我也感到困惑。
我认为(我强调,这是原创性研究 ,如果我错了,我肯定可能会失去声誉)的原因是, Close()
可能会失败,在打开资源时产生exception,而Dispose()
肯定会释放它们 。 这就是为什么一个Dispose()
应该总是保证一个Close()
调用 (对于双关语是抱歉的)。
MyResource r = new MyResource(); try { r.Write(new Whatever()); r.Close() finally { r.Dispose(); }
是的,我想微软在这个例子上滑了一下。 也许这个时间戳永远不会被刷新到文件。
明天我正在修理我的旧密码。
编辑:对不起Brannon,我不能评论你的答案,但你确定在finally
块上调用Close()
是个好主意吗? 我猜这个例外可能会破坏块的其余部分,这可能会包含重要的清理代码。
回复Brannon's:很好,只要在真正需要的时候不要忘记调用Close()
(例如,当处理stream – 对.NET中的SQL连接不太了解时)。
转到iDisposable,并打电话处置。 这将调用任何方法被configuration为实现“iDisposable.Dispose”,无论该函数是什么命名。
一般来说,我们在Close(),Abort()和Dispose()中面临问题,但让我告诉你们之间的差异。
1)ABORT: – 我不会build议使用这个,因为当中止被调用时,客户端将在不告诉服务器的情况下删除连接,所以服务器将等待一段时间(大约1分钟)。 如果您有批量请求,那么您不能使用abort(),因为它可能会导致有限的连接池超时。
2)closures: – closures是非常好的方式来closures连接,因为当closures连接时,它会调用服务器,并确认服务器也closures。
在这里,还有一件事要看。 在某些情况下,如果产生错误,那么在connection.close()中编写代码并不是一个好办法,因为那时通信状态将会出错。
3)处理: – 这是一个types的closures,但closures连接后,你不能再打开它。
所以试试这个方法,
private void CloseConnection(Client client) { if (client != null && client.State == CommunicationState.Opened) { client.Close(); } else { client.Abort(); } }