[英]How to implement IDisposable properly
在我作為開發人員的時候,我已經看到了很多C#代碼,它試圖通過將變量設置為null或者在類(例如DataSet)上調用Dispose()並在我自己的類Dispose()方法中幫助GC。一直在想是否需要在托管環境中實現它。
這個代碼在設計模式中是浪費時間嗎?
class MyClass : IDisposable
{
#region IDisposable Members
public void Dispose()
{
otherVariable = null;
if (dataSet != null)
{
dataSet.Dispose();
}
}
#endregion
}
GC 不會調用.Dispose()
(但它會調用finalize ~MyClass()
方法,您可以調用Dispose()
方法,以便在GC決定清理您的類時自動管理資源)。
您必須始終提供一種方法將內部資源(如DataSets
處理為使用您的類的代碼(並確保實際調用.Dispose()
或將構造函數包裝在using
)。 強烈建議在使用內部資源的類上使用IDisposable
。
來自MSDN :
此接口的主要用途是釋放非托管資源。 當不再使用該對象時,垃圾收集器會自動釋放分配給托管對象的內存。 但是,無法預測垃圾收集何時發生。 此外,垃圾收集器不了解非托管資源,例如窗口句柄,或打開文件和流。
public void Dispose()
{
otherVariable = null;
if (dataSet != null)
{
dataSet.Dispose();
dataSet = null;
}
}
不,處理方法不是浪費時間。
配置模式允許調用者在完成后立即清理類,而不是等待GC收集它。 對於普通堆內存,延遲並不重要,這就是為什么像String
這樣的基類沒有實現它。 然而,Dispose有用的是清理非托管資源。 在內部某處,Dataset類使用非托管資源,因此它提供了一種dispose方法,允許您在釋放非托管資源時通知它。
如果正確地遵循了模式,Dataset也將有一個終結器(或者某個子類),這意味着如果你沒有手動處理它,最終GC會運行,終結器將被調用並且非托管資源將被清除就這樣。 這個非托管資源可能很重要,想象一下,如果它是文件鎖或數據庫連接,你真的不想在重用數據庫連接之前等待GC運行。 Dispose提供了一種確定性的方法,可以在資源完成時清理資源,而不是依賴於非確定性GC。
至於在dispose方法中將變量設置為null。 幾乎所有情況都是毫無意義的。 將變量設置為null會刪除對該變量的引用,這將使其符合垃圾收集的條件(如果這是最后一個引用),但是當您正在處理該類時,您可能會超出范圍因此,無論如何內部類都將有資格收集。
如果您的類中有成員變量是您創建的一次性變量(不僅僅是您持有的引用),那么您應該始終從您自己的類的dispose方法調用dispose,但不要將它們設置為null。
不是完全。 如果您有一次性的成員變量,那么您可能應該像這樣處理它。 由於垃圾回收器無法保證在任何特定時間運行,因此您的對象可能比其正在進行的工作范圍更長。
將托管變量設置為null是浪費時間。 該對象不會更快地獲得GC。
垃圾車每周都會來到我的地區,但除非我把垃圾箱放到可以收集的地方,否則它不會收集我的垃圾。
您應該只刪除所有不需要的事件訂閱,引用和清除非托管處理程序。 然后垃圾收集器將處理其余的事情。
下面的示例顯示了實現IDisposable接口的一般最佳實踐。 參考: https : //msdn.microsoft.com/en-us/library/system.idisposable.dispose(v=vs.110).aspx
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.
protected virtual 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.
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.