9

我知道它用于释放非托管资源,但是,我对何时Dispose实际调用感到困惑。我知道它在块的末尾被using调用,但是当对象被垃圾收集时它也会被调用吗?

4

4 回答 4

11

如果你正确地实现了 IDisposable,你还应该包含一个终结器,它将在你的对象上调用 Dispose()。

如果你这样做,它将被 GC 调用。但是,尝试始终自己处理这些物品仍然是一个非常好的主意。

依赖终结器调用 Dispose 的最大问题是它会发生在您无法控制的另一个线程中。在某些情况下,这可能会产生令人讨厌的后果,包括导致 GC 线程中发生的异常,这是不好的,以及检查一个已处置的字段。这也是为什么在 Dispose() 方法中包含 GC.SuppressFinalize(this) 很重要的部分原因 - 一旦对象被释放,您就不想重新释放它。

于 2009-03-10T20:01:39.737 回答
3

Dispose 在几个地方被调用:

  1. 在 using 块的末尾。
  2. 当显式调用时(例如在 try{} finally{} 中。)

建议您在使用完资源后自己调用它,以更好地管理资源。

编辑:我错了。在垃圾收集期间不会调用 Dispose。见这篇文章。

于 2009-03-10T19:59:05.187 回答
2

Dispose() 在 Using 块的末尾被调用,以便您可以指望在对象超出范围时发生 Dispose 操作(例如关闭数据库连接)。就那么简单。

更新:在对 Dispose 的调用中 没有特定于非托管资源的内容(尽管这是一种常见用法)。

更新 2:关于 Reed Copsey 开始的线程有一些争论,这对于理解 IDisposable 很有用。我强烈推荐这篇文章给想要了解更多的人。

简而言之,IDisposable 类允许您通过 Dispose() 方法显式处理资源的释放(通常是非托管资源或数据库连接)。IDisposable 类实例应在“Using”块中创建,以确保实际调用 Dispose 方法。如果您没有这样做(或在“finally”块中显式调用它等),那么您的 Dispose 方法将不会被调用,并且您将孤立您想要清理的对象。在所有情况下,我都将 Disposable 类放在 Using blocks 中,你也应该这样做。

作为替代方案,您可以在终结器(类析构函数)中处理资源的清理。这将在类被 GC 时自动调用。这种方法的缺点是您不会明确控制何时清理对象并且需要处理一些线程问题。因此,例如,析构函数中的问题很难调试,因为它们是在不同的线程中异步调用的。唯一的好处是你不必像 Dispose 那样记住调用你的析构函数。当然,如果您总是使用 Using 块,这不是问题。

注意:我 ktrauberman、Reed 和 Pontus 已经提出了一些关于如何绕过我在下面提出的观点的好观点。这就是我所做的,但我不能说这是做事的唯一方法。实际上,Microsoft 甚至建议在某些情况下从您的 Finalizer 调用 Dispose()。但是,我将在此处留下讨论,以说明为什么遵循 Reed 的建议很重要:混合使用 Destructors 和 Dispose() 时要小心。

我不同意 Reed 的回答的地方在于,您应该通过在终结器中调用 Dispose() 来实现 IDisposable 类。这只是将两种不同的结构混为一谈,很可能会导致问题。例如,如果您确实在 Using 块中创建了 IDisposable 类实例在 Destructor 中调用了 Dispose(),它将被调用两次 - 可能会出现令人讨厌且难以调试的崩溃(同样 - 您无法控制GC)。(旁注:这实际上适用于一般的析构函数——在某些情况下,它们可以被多次调用!)

于 2009-03-10T19:58:06.050 回答
2

不,当对象被垃圾收集时,它不会被调用。如果你想要这种行为,你可以使用析构函数(终结器)和Dispose()从那里调用。

正如您所说,它被自动调用并结束了一个using块。

于 2009-03-10T19:59:23.660 回答