如何在C#中的Dispose()方法中配置托管资源?

我知道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. } } 

这意味着如果对象包含托管资源,我们也必须处理它,因为垃圾收集器不会清理它。

那是错误的。 垃圾收集器仍将清理您的托管资源。 终结器也严格用于清理非托管资源,因此SuppressFinalize()调用不会对您造成伤害。

而且由于你是IDisposable模式的新手,我会预料到你的下一个困惑点:写终结器。 在C#中,只应在处理全新的非托管资源时编写终结器。 因此,如果您有一个将System.Data.SqlClient.SqlConnection类型包装为数据访问层一部分的类, 则不应该为该类型编写终结器,因为您仍在处理相同类型的底层非托管资源:sql server数据库连接。 该资源的终结器已由基本SqlConnection类型处理。

另一方面,如果您正在为一种全新的数据库引擎构建ADO.Net提供程序,则需要在连接类中实现终结器,因为之前从未进行过。

这种一次性模式令人困惑 。 这是实现它的更好方法 :

步骤1.创建一个一次性类来封装您拥有的每个非托管资源。 这应该是非常罕见的,大多数人没有非托管资源来清理。 这个类只关心(pdf)它的非托管资源,并且应该有一个终结器。 实现看起来像这样:

 public class NativeDisposable : IDisposable { public void Dispose() { CleanUpNativeResource(); GC.SuppressFinalize(this); } protected virtual void CleanUpNativeResource() { // ... } ~NativeDisposable() { CleanUpNativeResource(); } // ... IntPtr _nativeResource; } 

步骤2.当class级持有其他一次性课程时,创建一个一次性课程。 这很容易实现,你不需要终结器。 在Dispose方法中,只需在其他一次性用品上调用Dispose。 在这种情况下,您不关心非托管资源:

 public class ManagedDisposable : IDisposable { // ... public virtual void Dispose() { _otherDisposable.Dispose(); } IDisposable _otherDisposable; } 

示例中的“Component”可以是其中之一,具体取决于它是否封装了非托管资源,或者它是否仅由其他可支配资源组成。

另请注意,压制终结并不意味着您要阻止垃圾收集器清理您的实例; 它只是意味着当垃圾收集器在您的实例中运行时,它不会调用为其定义的终结器。

也许更清楚一点。 GC.SuppressFinalize(this)仅影响this指针引用的对象,但不影响对象的任何成员。 也就是说,SuppressFinalize不会递归地应用于对象的成员。 当垃圾收集器回收Disposed对象的内存时,很可能没有对对象字段的活动引用。 由于您没有在对象的所有字段上调用GC.SuppressFinalize,因此垃圾收集器将在这些对象上调用finalize方法(如果存在)。 当它完成时,这完全取决于运行时,通常你应该让它做它的事情。

很抱歉,如果我误解了你的问题!!,但是如果你的类刚刚引用了其他托管类,并且那些对这些对象的引用不需要处理那么你的类不一定需要实现IDisposable。