釋放對象的模式(稱為釋放模式)對對象的生存期進行規定。
類型的 Dispose
方法應釋放它擁有的所有資源。 它還應該通過調用其父類型的 Dispose
方法釋放其基底類型擁有的所有資源。 父類型的 Dispose
方法應該釋放它擁有的所有資源,進而調用其父類型的 Dispose
方法,從而在整個基底類型階層中傳播此模式。 若要協助確保始終正確地清理資源,Dispose
方法應該可以多次調用而不引發異常。
對只使用託管資源的類型(如數組)實現 Dispose
方法並不能提高效能,原因是這些類型由記憶體回收行程自動回收。 應主要對使用本機資源的託管對象和向 .NET Framework 公開的 COM
對象使用 Dispose
方法。 使用本機資源的託管對象(如 FileStream
類)實現 IDisposable
介面。
| 重要事項 |
C++ 程式員不應該使用本主題。 而應參見 Destructors and Finalizers in Visual C++。 在 .NET Framework 2.0 版中,C++ 編譯器為實現資源的確定性處置提供支援,並且不允許直接實現 Dispose 方法。 |
Dispose
方法應為它要釋放的對象調用 SuppressFinalize
方法。 如果對象當前在終止隊列中,則 SuppressFinalize
會阻止調用其 Finalize
方法。 請記住,執行
Finalize
方法會降低效能。 如果
Dispose
方法已完成清理對象的工作,記憶體回收行程就不必調用對象的 Finalize
方法。
為 GC.KeepAlive
方法提供的程式碼範例示範了強行記憶體回收如何在回收對象的成員仍在執行時引起終結器運行。 在較長的 Dispose
方法末尾最好調用 KeepAlive
方法。
樣本
下面的程式碼範例示範為封裝非託管資源的類實現 Dispose
方法的建議設計模式。
資源類通常是從複雜的本機類或 API
派生的,而且必須進行相應的自訂。 使用這一代碼模式作為建立資源類的一個起始點,並根據封裝的資源提供必要的自訂。
Imports System<br />Imports System.IO<br />Class Program</p><p> Public Shared Sub Main()<br /> Try<br /> ' Initialize a Stream resource to pass<br /> ' to the DisposableResource class.<br /> Console.Write("Enter filename and its path: ")<br /> Dim fileSpec As String = Console.ReadLine<br /> Dim fs As FileStream = File.OpenRead(fileSpec)<br /> Dim TestObj As DisposableResource = New DisposableResource(fs)</p><p> ' Use the resource.<br /> TestObj.DoSomethingWithResource()</p><p> ' Dispose theresource.<br /> TestObj.Dispose()</p><p> Catch e As FileNotFoundException<br /> Console.WriteLine(e.Message)<br /> End Try<br /> End Sub<br />End Class</p><p>' This class shows how to use a disposable resource.<br />' The resource is first initialized and passed to<br />' the constructor, but it could also be<br />' initialized in the constructor.<br />' The lifetime of the resource does not<br />' exceed the lifetime of this instance.<br />' This type does not need a finalizer because it does not<br />' directly create a native resource like a file handle<br />' or memory in the unmanaged heap.<br />Public Class DisposableResource<br /> Implements IDisposable</p><p> Private _resource As Stream</p><p> Private _disposed As Boolean</p><p> ' The stream passed to the constructor<br /> ' must be readable and not null.<br /> Public Sub New(ByVal stream As Stream)<br /> MyBase.New()<br /> If (stream Is Nothing) Then<br /> Throw New ArgumentNullException("Stream is null.")<br /> End If<br /> If Not stream.CanRead Then<br /> Throw New ArgumentException("Stream must be readable.")<br /> End If<br /> _resource = stream<br /> Dim objTypeName As String = _resource.GetType.ToString<br /> _disposed = False<br /> End Sub</p><p> ' Demonstrates using the resource.<br /> ' It must not be already disposed.<br /> Public Sub DoSomethingWithResource()<br /> If _disposed Then<br /> Throw New ObjectDisposedException("Resource was disposed.")<br /> End If</p><p> ' Show the number of bytes.<br /> Dim numBytes As Integer = CType(_resource.Length, Integer)<br /> Console.WriteLine("Number of bytes: {0}", numBytes.ToString)<br /> End Sub</p><p> Public Overloads Sub Dispose() Implements IDisposable.Dispose<br /> Dispose(True)</p><p> ' Use SupressFinalize in case a subclass<br /> ' of this type implements a finalizer.<br /> GC.SuppressFinalize(Me)<br /> End Sub</p><p> Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)<br /> If Not _disposed Then</p><p> ' If you need thread safety, use a lock around these<br /> ' operations, as well as in your methods that use the resource.<br /> If disposing Then<br /> If (Not (_resource) Is Nothing) Then<br /> _resource.Dispose()<br /> End If<br /> Console.WriteLine("Object disposed.")<br /> End If</p><p> ' Indicates that the instance has been disposed.<br /> _resource = Nothing<br /> _disposed = True<br /> End If<br /> End Sub<br />End Class</p><p>