【发布时间】:2021-03-17 01:11:29
【问题描述】:
对不起,我之前问过一个类似的问题,并且有答案。但是我又一次遇到了这个话题,这让我大吃一惊。 所以,John Sharp 的书,Microsoft Visual C# Step by Step 9ed。第 2 部分,第 14 章。
引用:
class Example : IDisposable
{
private Resource scarce; // scarce resource to manage and dispose
private bool disposed = false; // flag to indicate whether the resource
// has already been disposed
~Example()
{
this.Dispose(false);
}
public virtual void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// release large, managed resource here
}
// release unmanaged resources here
this.disposed = true;
}
}
public void SomeBehavior() // example method
{
checkIfDisposed();
}
private void checkIfDisposed()
{
if (this.disposed)
{
throw new ObjectDisposedException('Example: object has been disposed');
}
}
}
请注意示例类的以下特性:
该类实现了 IDisposable 接口。
您的应用程序代码可以随时调用公共 Dispose 方法。
公共 Dispose 方法调用采用布尔参数的 Dispose 方法的受保护和重载版本,传递 值 true 作为参数。这个方法实际上执行了资源 处置。
析构函数调用受保护和重载版本的 Dispose 方法,该方法采用布尔参数,传递值 false 作为论据。析构函数只被垃圾调用 完成对象时的收集器。
您可以多次安全地调用受保护的 Dispose 方法。变量disposed表示该方法是否已经被 运行,是一种安全功能,以防止该方法试图 如果同时调用资源,则多次处理资源。 (您的应用程序可能会调用 Dispose,但在方法完成之前, 您的对象可能会受到垃圾收集和 Dispose 方法由 CLR 从析构函数再次运行。)资源是 仅在方法第一次运行时释放。
受保护的 Dispose 方法支持对托管资源(如大型数组)和非托管资源(如文件 处理)。如果 disposing 参数为 true,则此方法必须具有 从公共 Dispose 方法调用。在这种情况下,托管 资源和非托管资源全部释放。如果处置 参数为假,此方法必须已从 析构函数,垃圾收集器正在终结对象。在 在这种情况下,没有必要(或异常安全)释放 托管资源,因为它们将是或可能已经是, 由垃圾收集器处理,因此只有非托管资源 发布。
公共 Dispose 方法调用静态 GC.SuppressFinalize 方法。此方法阻止垃圾收集器调用 此对象上的析构函数,因为该对象已经 最终确定。
类的所有常规方法(例如 SomeBehavior)检查对象是否已经被丢弃。如果有,他们 抛出异常。
我用粗体突出了一段我不明白在什么情况下这是可能的。特别是这个:
您的应用程序可能会调用 Dispose,但在该方法完成之前, 您的对象可能会受到垃圾收集和 Dispose 由 CLR 从析构函数再次运行的方法。
我不明白。如果 Dispose 方法还没有完成,那么 this.disposed = true 的操作还没有执行,那么 this.disposed 仍然是 false。 当 this.Dispose (true) 运行时,对象将被垃圾回收。我已经接受了这个 - 方法仍然有效,在仍然有效的方法中有使用 this 关键字的操作,也就是说,我们仍然在使用这个对象,有使用这个对象的成员的操作(this .disposed = true),并且当方法 (this.Dispose (true)) 完成后,GC.SuppressFinalize (this) 代码应该可以工作,其中也包含 this 关键字,但由于某种原因,我们的对象仍然是主题像书中写的那样进行垃圾收集。
很好。让我们假设。
但是this.disposed仍然是false,当垃圾回收和析构函数调用this.Dispose(false)方法时,this.disposed字段不会起任何作用。
作者错了吗?他为什么要写disposed field的作用,并举例说明这个field没用?还是我疯了?
【问题讨论】:
-
实际上,终结器几乎不再使用(根据docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…)。
-
You can call the protected Dispose method safely multiple times. The variable disposed indicates whether the method has already been run and is a safety feature to prevent the method from attempting to dispose of the resources multiple times if it is called concurrently.请注意,如果 concurrent 他们的意思是“同时调用”,这是没有帮助的措辞。并行调用Dispose可能无法保证在某些情况下有效(我认为这是您要提出的观点)。 stackoverflow.com/questions/5024883/…