关闭并处置-呼叫哪个?
读完线程SqlCommand.Dispose是否足够?以及关闭和处置WCF服务我想知道是否有SqlConnection之类的类,或者是从Stream类继承的几个类之一,如果我关闭Dispose而不是Close,这有关系吗?
解决方案
回答
对于SqlConnection而言,从连接本身的角度来看,它们是等效的。根据Reflector的说法,Dispose()调用Close()并进行一些额外的释放内存的操作-主要是通过将成员设置为null来实现的。
对于Stream,它们实际上是等效的。 Stream.Dispose()仅调用Close()。
回答
我们确实需要调用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()几乎总是最佳选择!除非我们计划在不久的将来重用该对象。
回答
像往常一样,答案是:取决于情况。不同的类以不同的方式实现" 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块)进行操作。
回答
很快的建议就成了一个很长的答案。对不起。
正如tyler在他的好答案中指出的那样,调用Dispose()是一种很棒的编程实践。这是因为该方法应该"团结"在一起,释放所有需要的资源,因此不需要多余的开放资源。例如,如果我们向文件中写入了一些文本,但未能关闭文件(释放资源),则该文件将保持打开状态,直到GC出现并执行我们应做的一切之前,其他任何人都无法写入该文件。完毕。
现在,在某些情况下,将有特定于我们正在处理的类的"定型"方法,例如StreamWriter.Close(),它将覆盖TextWriter.Close()。实际上,它们通常更适合这种情况:例如,StreamWriter的Close()在对象的Dispose()之前先刷新流和基础编码器!凉爽的!
但是,浏览MSDN时,我们会发现,即使是Microsoft,有时也会被大量的关闭器和处置器弄糊涂。例如,在此网页中,在某些示例中,在隐式Dispose()
之前调用Close()(如果我们不理解其隐式原因,请参见using语句),尤其是它们不会打扰到。为什么会这样呢?我也感到困惑。
我想到的原因(我强调,这是原始研究,如果我错了,我肯定会丢掉声誉)是因为Close()可能会失败,并在打开资源的同时产生异常,而Dispose()一定会释放他们。这就是为什么Dispose()应该始终维护Close()调用的原因(对双关语表示抱歉)。
MyResource r = new MyResource(); try { r.Write(new Whatever()); r.Close() finally { r.Dispose(); }
是的,我想微软会漏掉一个例子。也许该时间戳永远不会刷新到文件中。
我明天要修正我的旧代码。
编辑:对不起,布兰农,我无法对回答发表评论,但是我们确定在" finally"块上调用" Close()"是个好主意吗?我猜一个例外可能会破坏其余的块,其中可能包含重要的清理代码。
回答Brannon的问题:太好了,只是不要忘了在确实需要时(例如,在处理流对.NET中的SQL连接了解不多时)调用Close()。
回答
我想澄清这种情况。
根据Microsoft的准则,在适当的地方提供Close
方法是一个好习惯。这是《框架设计指南》的引文
Consider providing method Close(), in addition to the Dispose(), if close is standard terminology in the area. When doing so, it is important that you make the Close implementation identical to Dispose ...
在大多数情况下,Close
和Dispose
方法是等效的。在使用SqlConnectionObject的情况下,Close和Dispose之间的主要区别是:
An application can call Close more than one time. No exception is generated. If you called Dispose method SqlConnection object state will be reset. If you try to call any method on disposed SqlConnection object, you will receive exception.
说:
- 如果一次使用连接对象,则使用
Dispose
。 - 如果必须重用连接对象,请使用"关闭"方法。
回答
将类型转换为iDisposable,然后对其进行调用处理。这将调用配置为实现" iDisposable.Dispose"的任何方法,而不管该函数的名称是什么。