我知道Dispose()适用于非托管资源,不需要等待垃圾收集器完成对象时,应该在不再需要时处理资源。
但是,在处理对象时,它会抑制垃圾收集器的完成(GC.SuppressFinalize(this);在下面的代码中)。这意味着如果对象包含托管资源,我们也必须照顾它,因为垃圾收集器不会清理它。
在下面的示例代码中(来自MSDN),“Component”是一个托管资源,我们为此资源调用dispose()(component.Dispose())。我的问题是,我们如何为作为托管资源的Component类实现此方法?我们应该使用像Collect()这样的东西来捅垃圾收集器来清理这部分吗?
任何想法都会受到赞赏。感谢。
以下是我正在查看的代码来自MSDN:
using System;
using System.ComponentModel;
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}
答案 0 :(得分:15)
那种一次性模式是confusing。这是实现它的a better way:
步骤1。创建一个一次性类来封装您拥有的每个非托管资源。这应该是非常罕见的,大多数人没有非托管资源来清理。这个类only cares (pdf)关于它的非托管资源,应该有一个终结器。实现如下:
public class NativeDisposable : IDisposable {
public void Dispose() {
CleanUpNativeResource();
GC.SuppressFinalize(this);
}
protected virtual void CleanUpNativeResource() {
// ...
}
~NativeDisposable() {
CleanUpNativeResource();
}
// ...
IntPtr _nativeResource;
}
第2步。当班级持有其他一次性课程时,创建一个一次性班级。这很容易实现,你不需要终结器。在Dispose方法中,只需在其他一次性用品上调用Dispose。在这种情况下,您不关心非托管资源:
public class ManagedDisposable : IDisposable {
// ...
public virtual void Dispose() {
_otherDisposable.Dispose();
}
IDisposable _otherDisposable;
}
示例中的“Component”可以是其中之一,具体取决于它是否封装了非托管资源,还是仅包含其他可支配资源。
另请注意,压制终结并不意味着您要阻止垃圾收集器清理您的实例;它只是意味着当垃圾收集器在你的实例中运行时,它不会调用为它定义的终结器。
答案 1 :(得分:11)
这意味着如果对象包含托管资源,我们也必须处理它,因为垃圾收集器不会清理它。
这是错误的。垃圾收集器仍将清理您的托管资源。终结器也严格用于清理非托管资源,因此SuppressFinalize()调用不会对您造成伤害。
由于你是IDisposable模式的新手,我会预料到你的下一个困惑点:写终结者。在C#中,只应在处理全新的非托管资源时编写终结器。因此,如果你有一个将System.Data.SqlClient.SqlConnection类型包装为数据访问层一部分的类,你应该不为该类型编写终结器,因为你仍然处理相同类型的底层非托管资源:sql server数据库连接。该资源的终结器已由基本SqlConnection类型处理。
另一方面,如果您正在为一种全新的数据库引擎构建ADO.Net提供程序,则需要在连接类中实现终结器,因为之前从未进行过。
答案 2 :(得分:1)
也许更清楚一点。 GC.SuppressFinalize(this)仅影响this指针引用的对象,但不影响对象的任何成员。也就是说,SuppressFinalize不会递归地应用于对象的成员。当垃圾收集器回收Disposed对象的内存时,很可能没有对对象字段的活动引用。由于您没有在对象的所有字段上调用GC.SuppressFinalize,因此垃圾收集器将在这些对象上调用finalize方法(如果存在)。当它完成时,这完全取决于运行时,通常你应该让它做它的事情。
答案 3 :(得分:0)
很抱歉,如果我误解了你的问题!!,但是如果你的类只引用了其他托管类,并且那些对这些对象的引用不需要处理,那么你的类不一定需要实现IDisposable。