Dispose()用于清理托管资源?
在这个答案中,我发现,
在代码中使用Dispose / Finalize模式时,清除Finalize方法中的非托管资源和Dispose方法中的托管资源。
后来我发现这篇关于敲定和处理的好文章 ,并对它们有了清晰的认识。 本文有以下代码( 第3页 ),用于解释概念:
class Test : IDisposable { private bool isDisposed = false; ~Test() { Dispose(false); } protected void Dispose(bool disposing) { if (disposing) { // Code to dispose the managed resources of the class } // Code to dispose the un-managed resources of the class isDisposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } }
但在此之下,出现了相同的注释(我在本问题开头所包含的内容)。
Dispose / Finalize模式Microsoft建议您在使用非托管资源时实现Dispose和Finalize。 然后,正确的顺序是开发人员调用Dispose。 即使开发人员忽略了显式调用Dispose方法,也会在对象被垃圾回收时运行Finalize实现并仍然释放资源。 Francesco Balena在他的博客中写道:只有当你的类型调用分配非托管资源(包括非托管内存)的非托管代码并返回最终必须用来释放资源的句柄时,才应使用Dispose / Finalize模式。只需处理和终止必须通过在他们处理或完成他们自己的成员之后调用他们的父母各自的方法来链接到他们的父对象“。 简单地说,在代码中使用Dispose / Finalize模式时,清除Finalize方法中的非托管资源和Dispose方法中的托管资源。
现在我又困惑了。 在整篇文章和代码示例中,显示应在Dispose()
释放非托管资源。 但那个评论的相关性是什么?
编辑:
正如确认这一行:
简单地说,当在代码中使用Dispose / Finalize模式时,清理Finalize方法中的非托管资源和Dispose方法中的托管资源。
是错误的,我编辑了这个答案 。
看得很简单。
- 如果您正在处理非托管资源 – 实现
Dispose
和Finalize
。 开发人员要调用Dispose
,以便在资源不再需要时立即释放资源。 如果他们忘记调用Dispose
那么Framework会在自己的GC循环中调用finalize(通常会花费自己的甜蜜时间)。 - 如果您不处理非托管资源 – 那么就不要做任何事情。 不要实现
Finalize
和Dispose
。 - 如果您的对象在内部使用Disposable对象 – 如果您创建并保留对实现
Dispose()
且尚未处置的类型的任何对象的引用,则实现Dispose()
。
一些经典的例子:
System.IO.FileStream
对象管理文件的锁/流句柄。 所以它实现了dispose和finalize。 如果开发人员处理它,那么另一个程序可以立即访问它。 如果他忘记处理它,那么Framework最终确定它并在GC循环中关闭句柄。
System.Text.StringBuilder
没有任何非托管资源。 所以没有处理没有最终确定。
就模式而言,它意味着什么
// Code to dispose the managed resources of the class
是调用您拥有的任何.NET对象的Dispose方法作为该类中的组件
和
// Code to dispose the un-managed resources of the class
意味着关闭原始句柄和指针。 这是您的更新代码和示例
class Test : IDisposable { private bool isDisposed = false; ~Test() { Dispose(false); } protected void Dispose(bool disposing) { if (disposing) { // Code to dispose the managed resources of the class internalComponent1.Dispose(); internalComponent2.Dispose(); } // Code to dispose the un-managed resources of the class CloseHandle(handle); handle = IntPtr.Zero; isDisposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } }
这是一个解释它的老问题
如果Foo
有资源可以从确定性清理中受益,但没有一个可以在终结器中有用地清理,它应该实现IDisposable
但不应该覆盖Finalize
或者有一个析构函数。 如果一个类拥有多个资源,并且至少有一个资源可以在终结器中清理,那么可以在终结器中清理的每个离散资源都应该封装到自己的Finalizer / destructor配备的对象中(可以在protected nested class),包含这些资源的类应该包含对包装器对象的引用。 完成后,外部类将适合具有Dispose
方法但没有终结器/析构函数的类的模式。