closures和处置 – 要调用哪个?

读过线程SqlCommand.Dispose是否足够? 和closures和处置一个WCF服务我想知道类如SqlConnection或从Stream类inheritance的几个类之一,如果我closuresDispose而不是closures它是否重要?

我想澄清这种情况。

根据Microsoft的指导方针,在合适的地方提供Close方法是一个很好的做法。 以下是框架devise指南的引用

考虑提供方法Close() ,除了Dispose() ,如果close是该领域的标准术语。 这样做时,将“ Close实现与“ Dispose Close相同是非常重要的。

在大多数情况下, CloseDispose方法是等价的。 在SqlConnectionObject的情况下CloseDispose主要区别是:

应用程序可以多次调用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(); } }