关于.net:关闭并处理-调用哪个?

关于.net:关闭并处理-调用哪个?

Close and Dispose - which to call?

读完线程SqlCommand.Dispose是否足够? 以及关闭和处置WCF服务我想知道诸如SqlConnection之类的类还是从Stream类继承的几个类之一,如果我关闭Dispose而不是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 ...

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

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
  • 如果必须重用连接对象,
    使用Close方法。

像往常一样,答案是:取决于情况。不同的类以不同的方式实现IDisposable,这取决于您进行必要的研究。

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

1
2
3
4
5
6
7
8
9
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块)来执行此操作。


您确实需要调用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()几乎总是您的最佳选择!除非您计划在不久的将来重用该对象。


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

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


这可能很快就会成为一个很长的答案。抱歉。

正如tyler在他的好答案中指出的那样,调用Dispose()是一种很棒的编程习惯。这是因为该方法应该"聚集在一起"释放所有需要的资源,因此不需要多余的开放资源。例如,如果您向文件中写入了一些文本,但未能关闭文件(释放资源),则该文件将保持打开状态,直到GC出现并执行您应做的一切之前,其他任何人都无法写入该文件。完成。

现在,在某些情况下,将有一些特定于您正在处理的类的"完成"方法,例如StreamWriter.Close(),它会覆盖TextWriter.Close()。实际上,它们通常更适合这种情况:例如,StreamWriter的Close()在对象的Dispose()之前刷新流和基础编码器!凉!

但是,浏览MSDN时,您会发现,即使是Microsoft,有时也会因众多的关闭器和处置器而感到困惑。例如,在此网页中,在某些示例中,Close()在隐式Dispose()之前被调用(如果您不理解为什么它是隐式的,请参阅using语句),尤其是它们不会打扰。为什么会这样呢?我也感到困惑。

我想到的原因(并且,我强调,这是原始研究,如果我错了,我肯定会丢掉声誉)是Close()可能失败,在保持资源开放的同时产生异常,而Dispose()肯定会释放它们。这就是为什么Dispose()应该始终维护Close()调用的原因(对双关语很抱歉)。

1
2
3
4
5
6
7
8
9
MyResource r = new MyResource();

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

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

是的,我想微软会漏掉一个例子。也许该时间戳永远不会刷新到文件中。

我明天要修正旧代码。

编辑:对不起,布兰农,我无法评论您的答案,但是您确定在finally块上调用Close()是个好主意吗?我猜一个例外可能会破坏其余的块,其中可能包含重要的清理代码。

回答Brannon的问题:太好了,只是不要忘记在真正需要时调用Close()(例如,在处理流时-对.NET中的SQL连接了解不多)。


通常,我们在Close(),Abort()和Dispose()中面临问题,但让我告诉您它们之间的区别。

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

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

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

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

因此,尝试这种方式,

1
2
3
4
5
6
7
8
9
10
11
private void CloseConnection(Client client)
    {
        if (client != null && client.State == CommunicationState.Opened)
        {
            client.Close();
        }
        else
        {
            client.Abort();
        }
    }


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


推荐阅读