如果我的类实现了 IDisposable,为什么我需要终结器
本文关键字:为什么 我的 实现 IDisposable 如果 | 更新日期: 2023-09-27 18:35:59
那么下面的一次性模式呢?
using System;
public class MyClass : IDisposable
{
public void Dispose()
// Implement IDisposable
{
//just do the cleanup
GC.SuppressFinalize(this);
}
}
更新
我的意思是说,如果没有非托管资源,我需要终结器吗?上面的一次性模式还不够好吗?是的,即使用户/开发人员不调用释放,GC 调用默认情况下也不会释放吗?
那么 GC 调用释放器和终结器的顺序呢?
有关更多详细信息,请参阅此问题。
换句话说,当我们有终结器时,为什么我们调用 false 作为参数的 Dispose
?
从 http://msdn.microsoft.com/en-us/magazine/cc163392.aspx#S2 来看,似乎始终建议从终结器而不是托管引用中释放非托管资源。
始终建议从 Dispose 方法释放非托管资源。阅读这篇文章时,我仍然没有得到全部要点。
但是,如果没有非托管资源,则以下模式应该有效。
根据 msdn.microsoft.com/en-us/magazine/cc163392.aspx#S2 的说法,msdn.microsoft.com/en-us/library/fs2xkftw.aspx 建议在终结器中释放本机资源,并且所有资源都使用 dispose()。如果显式调用dispose(),它可以抑制终结器,即如果没有本机资源,我们不需要终结器。
using System;
public class MyClass : IDisposable
{
private bool disposed = false;
protected virtual void Dispose(bool suppressFinalize)
{
if (!disposed)
{
//Just do the cleanup
//and release resources
disposed = true;
}
if (!suppressFinalize)
{
GC.SuppressFinalize(this);
}
}
public void Dispose()
// Implement IDisposable
{
Dispose(true);
}
~MyClass() // the finalizer
{
Dispose(false);
}
}
因为您可能直接引用了非托管资源(例如 Windows 句柄),并且即使没有人调用 Dispose
,您也希望释放它们。
不过,这种情况非常罕见 - 通常您实际上只能通过其他托管类型间接引用非托管资源,这些托管类型在需要时将具有终结器。
> .Net 中的 Finalization + IDisposable
实际上是两个不同的问题,试图用单一的一次性模式来解决。
- 托管资源清理
- 非托管资源清理
非托管资源是不受 CLR 和垃圾回收器控制的项目。 诸如文件句柄,从PInvoke返回的内存等项目... 如果用户代码未显式释放这些资源,它们将泄漏并在进程生存期的剩余时间内存在。 释放他们至关重要。
这就是终结器的用武之地。 它将在 CLR 收集对象之前在对象上运行。 这不需要使用者遵循一次性模式,因此是确保释放非托管资源以防止泄漏的良好后备。
如果代码不包含任何直接持有的非托管资源,则没有理由使用终结器。 保存非托管资源的代码负责拥有终结器。