實作 Dispose 方法Implementing a Dispose method

您實作 Dispose 方法,以釋放您的應用程式所使用的非受控資源。You implement a Dispose method to release unmanaged resources used by your application. .NET 記憶體回收行程不會配置或釋放 Unmanaged 記憶體。The .NET garbage collector does not allocate or release unmanaged memory.

處置物件的模式稱為處置模式,會在物件的存留期上安排順序。The pattern for disposing an object, referred to as a dispose pattern, imposes order on the lifetime of an object. 處置模式僅適用於存取 Unmanaged 資源的物件,例如檔案和管道控制碼、註冊控制代碼、等候控制代碼,或是 Unmanaged 記憶體區塊的指標。The dispose pattern is used only for objects that access unmanaged resources, such as file and pipe handles, registry handles, wait handles, or pointers to blocks of unmanaged memory. 這是因為記憶體回收行程在回收未使用的 Managed 物件方面相當有效率,但是它無法回收 Unmanaged 物件。This is because the garbage collector is very efficient at reclaiming unused managed objects, but it is unable to reclaim unmanaged objects.

處置模式有兩種:The dispose pattern has two variations:

若要確保資源永遠都能適當清除,Dispose 方法應該能夠被呼叫多次而不會擲回例外狀況。To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.

此處所提供的 GC.KeepAlive 方法程式碼範例,顯示積極記憶體回收如何在被回收的物件仍在執行時,即讓完成項開始執行。The code example provided for the GC.KeepAlive method shows how aggressive garbage collection can cause a finalizer to run while a member of the reclaimed object is still executing. 在冗長的 KeepAlive 方法結尾處呼叫 Dispose 方法,這是個不錯的做法。It is a good idea to call the KeepAlive method at the end of a lengthy Dispose method.

Dispose() 和 Dispose(Boolean)Dispose() and Dispose(Boolean)

IDisposable 介面要求實作單一無參數方法 DisposeThe IDisposable interface requires the implementation of a single parameterless method, Dispose. 不過,處置模式要求實作兩種 Dispose 方法:However, the dispose pattern requires two Dispose methods to be implemented:

  • 公用非虛擬 (在 Visual Basic 中為 NonInheritable) 的 IDisposable.Dispose 實作,而且沒有任何參數。A public non-virtual (NonInheritable in Visual Basic) IDisposable.Dispose implementation that has no parameters.

  • 受保護的虛擬 (Visual Basic 中為 Overridable) Dispose 方法,其簽章為:A protected virtual (Overridable in Visual Basic) Dispose method whose signature is:

    protected virtual void Dispose(bool disposing)
    
    Protected Overridable Sub Dispose(disposing As Boolean)
    

Dispose() 多載The Dispose() overload

由於這個公用、非虛擬 (在 Visual Basic 中為 NonInheritable)、無參數的 Dispose 方法是由類型消費者所呼叫,其用途是釋放 Unmanaged 資源並指出完成項 (如果有的話) 不需要執行。Because the public, non-virtual (NonInheritable in Visual Basic), parameterless Dispose method is called by a consumer of the type, its purpose is to free unmanaged resources and to indicate that the finalizer, if one is present, doesn't have to run. 因此,它擁有標準實作:Because of this, it has a standard implementation:

public void Dispose()
{
   // Dispose of unmanaged resources.
   Dispose(true);
   // Suppress finalization.
   GC.SuppressFinalize(this);
}
Public Sub Dispose() _
           Implements IDisposable.Dispose
   ' Dispose of unmanaged resources.
   Dispose(True)
   ' Suppress finalization.
   GC.SuppressFinalize(Me)
End Sub

Dispose 方法會執行所有物件清除,所以記憶體回收行程不需要再呼叫物件的 Object.Finalize 覆寫。The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object.Finalize override. 因此,呼叫 SuppressFinalize 方法會防止記憶體回收行程執行完成項。Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. 如果類型沒有完成項,則呼叫 GC.SuppressFinalize 沒有作用。If the type has no finalizer, the call to GC.SuppressFinalize has no effect. 請注意,實際釋放 Unmanaged 資源的工作是由 Dispose 方法的第二個多載執行。Note that the actual work of releasing unmanaged resources is performed by the second overload of the Dispose method.

Dispose(Boolean) 多載The Dispose(Boolean) overload

在第二個多載中,disposing 參數為 Boolean,它會指出方法呼叫是來自 Dispose 方法 (其值為 true) 或是來自完成項 (其值為 false)。In the second overload, the disposing parameter is a Boolean that indicates whether the method call comes from a Dispose method (its value is true) or from a finalizer (its value is false).

方法的主體是由兩個程式碼區塊所構成:The body of the method consists of two blocks of code:

  • 釋放 Unmanaged 資源的區塊。A block that frees unmanaged resources. 不論 disposing 參數的值為何,這個區塊都會執行。This block executes regardless of the value of the disposing parameter.

  • 釋放 Managed 資源的條件性區塊。A conditional block that frees managed resources. 如果 disposing 的值為 true,這個區塊就會執行。This block executes if the value of disposing is true. 它所釋放的 Managed 資源可能包括:The managed resources that it frees can include:

    實作 IDisposable 的受控物件。Managed objects that implement IDisposable. 條件式區塊可以用來呼叫其 Dispose 實作。The conditional block can be used to call their Dispose implementation. 如果您已使用安全控制代碼包裝 Unmanaged 資源,則應該在這裡呼叫 SafeHandle.Dispose(Boolean) 實作。If you have used a safe handle to wrap your unmanaged resource, you should call the SafeHandle.Dispose(Boolean) implementation here.

    耗用大量記憶體或耗用少量資源的 Managed 物件。Managed objects that consume large amounts of memory or consume scarce resources. 如果它們是之非由記憶體回收行程,在 Dispose 方法中明確釋放這些物件的速度,會比由記憶體回收行程以非決定性的方式回收來得快。Freeing these objects explicitly in the Dispose method releases them faster than if they were reclaimed non-deterministically by the garbage collector.

如果方法呼叫來自完成項 (也就是如果 disposingfalse),則只會執行釋放 Unmanaged 資源的程式碼。If the method call comes from a finalizer (that is, if disposing is false), only the code that frees unmanaged resources executes. 由於記憶體回收行程在最終處理期間終結 Managed 物件的順序並未定義,使用 Dispose 值呼叫此 false 多載可防止完成項嘗試釋放可能已經回收的 Managed 資源。Because the order in which the garbage collector destroys managed objects during finalization is not defined, calling this Dispose overload with a value of false prevents the finalizer from trying to release managed resources that may have already been reclaimed.

實作基底類別的處置模式Implementing the dispose pattern for a base class

如果您實作基底類別的處置模式,則必須提供下列項目:If you implement the dispose pattern for a base class, you must provide the following:

重要

您應該針對實作 Dispose() 並且不是 sealed (在 Visual Basic 中為 NotInheritable) 的所有基底類別實作此模式。You should implement this pattern for all base classes that implement Dispose() and are not sealed (NotInheritable in Visual Basic).

  • 呼叫 Dispose 方法的 Dispose(Boolean) 實作。A Dispose implementation that calls the Dispose(Boolean) method.

  • 實際釋放資源的 Dispose(Boolean) 方法。A Dispose(Boolean) method that performs the actual work of releasing resources.

  • 衍生自包裝您的 Unmanaged 資源之 SafeHandle 的類別 (建議使用),或式 Object.Finalize 方法的覆寫。Either a class derived from SafeHandle that wraps your unmanaged resource (recommended), or an override to the Object.Finalize method. SafeHandle 類別會提供完成項,讓您不必自行撰寫程式碼。The SafeHandle class provides a finalizer that frees you from having to code one.

以下一般模式將會實作使用安全控制代碼之基底類別的處置模式。Here's the general pattern for implementing the dispose pattern for a base class that uses a safe handle.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   // Instantiate a SafeHandle instance.
   SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);
   
   // Public implementation of Dispose pattern callable by consumers.
   public void Dispose()
   { 
      Dispose(true);
      GC.SuppressFinalize(this);           
   }
   
   // Protected implementation of Dispose pattern.
   protected virtual void Dispose(bool disposing)
   {
      if (disposed)
         return; 
      
      if (disposing) {
         handle.Dispose();
         // Free any other managed objects here.
         //
      }
      
      disposed = true;
   }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class BaseClass : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a SafeHandle instance.
   Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(True)
      GC.SuppressFinalize(Me)           
   End Sub
   
   ' Protected implementation of Dispose pattern.
   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Return
      
      If disposing Then
         handle.Dispose()
         ' Free any other managed objects here.
         '
      End If
      
      disposed = True
   End Sub
End Class

注意

上一個範例使用 SafeFileHandle 物件來說明模式;可改用任何衍生自 SafeHandle 的物件。The previous example uses a SafeFileHandle object to illustrate the pattern; any object derived from SafeHandle could be used instead. 請注意,該範例未正確地執行個體化其 SafeFileHandle 物件。Note that the example does not properly instantiate its SafeFileHandle object.

以下一般模式將會實作覆寫 Object.Finalize 之基底類別的處置模式。Here's the general pattern for implementing the dispose pattern for a base class that overrides Object.Finalize.

using System;

class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   
   // Public implementation of Dispose pattern callable by consumers.
   public void Dispose()
   { 
      Dispose(true);
      GC.SuppressFinalize(this);           
   }
   
   // Protected implementation of Dispose pattern.
   protected virtual void Dispose(bool disposing)
   {
      if (disposed)
         return; 
      
      if (disposing) {
         // Free any other managed objects here.
         //
      }
      
      // Free any unmanaged objects here.
      //
      disposed = true;
   }

   ~BaseClass()
   {
      Dispose(false);
   }
}
Class BaseClass : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   
   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(True)
      GC.SuppressFinalize(Me)           
   End Sub
   
   ' Protected implementation of Dispose pattern.
   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Return
      
      If disposing Then
         ' Free any other managed objects here.
         '
      End If
      
      ' Free any unmanaged objects here.
      '
      disposed = True
   End Sub

   Protected Overrides Sub Finalize()
      Dispose(False)      
   End Sub
End Class

注意

在 C# 中,您會透過定義解構函式來覆寫 Object.FinalizeIn C#, you override Object.Finalize by defining a destructor.

實作衍生類別的處置模式Implementing the dispose pattern for a derived class

從實作 IDisposable 介面的類別衍生的類別不應該實作 IDisposable,因為 IDisposable.Dispose 的基底類別實作會由其衍生類別繼承。A class derived from a class that implements the IDisposable interface shouldn't implement IDisposable, because the base class implementation of IDisposable.Dispose is inherited by its derived classes. 因此,若要實作衍生類別的處置模式,請改為提供下列項目:Instead, to implement the dispose pattern for a derived class, you provide the following:

  • 覆寫基底類別方法及實際釋放衍生類別之資源的 protected Dispose(Boolean) 方法。A protected Dispose(Boolean) method that overrides the base class method and performs the actual work of releasing the resources of the derived class. 此方法也應呼叫基底類別的 Dispose(Boolean) 方法,並傳遞其處置狀態作為引數。This method should also call the Dispose(Boolean) method of the base class and pass its disposing status for the argument.

  • 衍生自包裝您的 Unmanaged 資源之 SafeHandle 的類別 (建議使用),或式 Object.Finalize 方法的覆寫。Either a class derived from SafeHandle that wraps your unmanaged resource (recommended), or an override to the Object.Finalize method. SafeHandle 類別會提供完成項,讓您不必自行撰寫程式碼。The SafeHandle class provides a finalizer that frees you from having to code one. 如果您提供完成項,則它應該呼叫 Dispose(Boolean) 多載且 disposing 引數為 falseIf you do provide a finalizer, it should call the Dispose(Boolean) overload with a disposing argument of false.

以下一般模式將會實作使用安全控制代碼之衍生類別的處置模式:Here's the general pattern for implementing the dispose pattern for a derived class that uses a safe handle:

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class DerivedClass : BaseClass
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   // Instantiate a SafeHandle instance.
   SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

   // Protected implementation of Dispose pattern.
   protected override void Dispose(bool disposing)
   {
      if (disposed)
         return; 
      
      if (disposing) {
         handle.Dispose();
         // Free any other managed objects here.
         //
      }
      
      // Free any unmanaged objects here.
      //

      disposed = true;
      // Call base class implementation.
      base.Dispose(disposing);
   }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class DerivedClass : Inherits BaseClass 
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a SafeHandle instance.
   Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

   ' Protected implementation of Dispose pattern.
   Protected Overrides Sub Dispose(disposing As Boolean)
      If disposed Then Return
      
      If disposing Then
         handle.Dispose()
         ' Free any other managed objects here.
         '
      End If
      
      ' Free any unmanaged objects here.
      '
      disposed = True
      
      ' Call base class implementation.
      MyBase.Dispose(disposing)
   End Sub
End Class

注意

上一個範例使用 SafeFileHandle 物件來說明模式;可改用任何衍生自 SafeHandle 的物件。The previous example uses a SafeFileHandle object to illustrate the pattern; any object derived from SafeHandle could be used instead. 請注意,該範例未正確地執行個體化其 SafeFileHandle 物件。Note that the example does not properly instantiate its SafeFileHandle object.

以下一般模式將會實作覆寫 Object.Finalize 之衍生類別的處置模式:Here's the general pattern for implementing the dispose pattern for a derived class that overrides Object.Finalize:

using System;

class DerivedClass : BaseClass
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   
   // Protected implementation of Dispose pattern.
   protected override void Dispose(bool disposing)
   {
      if (disposed)
         return; 
      
      if (disposing) {
         // Free any other managed objects here.
         //
      }
      
      // Free any unmanaged objects here.
      //
      disposed = true;
      
      // Call the base class implementation.
      base.Dispose(disposing);
   }

   ~DerivedClass()
   {
      Dispose(false);
   }
}
Class DerivedClass : Inherits BaseClass
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   
   ' Protected implementation of Dispose pattern.
   Protected Overrides Sub Dispose(disposing As Boolean)
      If disposed Then Return
      
      If disposing Then
         ' Free any other managed objects here.
         '
      End If
      
      ' Free any unmanaged objects here.
      '
      disposed = True

      ' Call the base class implementation.
      MyBase.Dispose(disposing)
   End Sub
   
   Protected Overrides Sub Finalize()
      Dispose(False)
   End Sub 
End Class

注意

在 C# 中,您會透過定義解構函式來覆寫 Object.FinalizeIn C#, you override Object.Finalize by defining a destructor.

使用安全控制代碼Using safe handles

撰寫物件完成項的程式碼是一項複雜的工作,若未正確撰寫,可能會造成問題。Writing code for an object's finalizer is a complex task that can cause problems if not done correctly. 因此,建議您建構 System.Runtime.InteropServices.SafeHandle 物件,而不要實作完成項。Therefore, we recommend that you construct System.Runtime.InteropServices.SafeHandle objects instead of implementing a finalizer.

衍生自 System.Runtime.InteropServices.SafeHandle 類別的類別會在不受干擾的情況下,藉由指派和釋放控制代碼的方式簡化物件存留期的問題。Classes derived from the System.Runtime.InteropServices.SafeHandle class simplify object lifetime issues by assigning and releasing handles without interruption. 這些類別包含重要的完成項,該完成項保證會在應用程式定義域卸載時執行。They contain a critical finalizer that is guaranteed to run while an application domain is unloading. 如需使用安全控制代碼之優點的詳細資訊,請參閱System.Runtime.InteropServices.SafeHandleFor more information about the advantages of using a safe handle, see System.Runtime.InteropServices.SafeHandle. Microsoft.Win32.SafeHandles 命名空間中的下列衍生類別會提供安全控制代碼:The following derived classes in the Microsoft.Win32.SafeHandles namespace provide safe handles:

使用安全控制代碼實作基底類別的處置模式Using a safe handle to implement the dispose pattern for a base class

下列範例將說明使用安全控制代碼封裝 Unmanaged 資源之基底類別 DisposableStreamResource 的處置模式。The following example illustrates the dispose pattern for a base class, DisposableStreamResource, that uses a safe handle to encapsulate unmanaged resources. 它會定義 DisposableResource 類別,該類別使用 SafeFileHandle 包裝代表開啟檔案的 Stream 物件。It defines a DisposableResource class that uses a SafeFileHandle to wrap a Stream object that represents an open file. DisposableResource 方法還包含單一屬性 Size,該屬性會傳回檔案資料流中的位元組總數。The DisposableResource method also includes a single property, Size, that returns the total number of bytes in the file stream.

using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Runtime.InteropServices;

public class DisposableStreamResource : IDisposable
{
   // Define constants.
   protected const uint GENERIC_READ = 0x80000000;
   protected const uint FILE_SHARE_READ = 0x00000001;
   protected const uint OPEN_EXISTING = 3;
   protected const uint FILE_ATTRIBUTE_NORMAL = 0x80;
   protected IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
   private const int INVALID_FILE_SIZE = unchecked((int) 0xFFFFFFFF);
   
   // Define Windows APIs.
   [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode)]
   protected static extern IntPtr CreateFile (
                                  string lpFileName, uint dwDesiredAccess, 
                                  uint dwShareMode, IntPtr lpSecurityAttributes, 
                                  uint dwCreationDisposition, uint dwFlagsAndAttributes, 
                                  IntPtr hTemplateFile);
   
   [DllImport("kernel32.dll")]
   private static extern int GetFileSize(SafeFileHandle hFile, out int lpFileSizeHigh);
    
   // Define locals.
   private bool disposed = false;
   private SafeFileHandle safeHandle; 
   private long bufferSize;
   private int upperWord;
   
   public DisposableStreamResource(string filename)
   {
      if (filename == null)
         throw new ArgumentNullException("The filename cannot be null.");
      else if (filename == "")
         throw new ArgumentException("The filename cannot be an empty string.");
            
      IntPtr handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
                                 IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
                                 IntPtr.Zero);
      if (handle != INVALID_HANDLE_VALUE)
         safeHandle = new SafeFileHandle(handle, true);
      else
         throw new FileNotFoundException(String.Format("Cannot open '{0}'", filename));
      
      // Get file size.
      bufferSize = GetFileSize(safeHandle, out upperWord); 
      if (bufferSize == INVALID_FILE_SIZE)
         bufferSize = -1;
      else if (upperWord > 0) 
         bufferSize = (((long)upperWord) << 32) + bufferSize;
   }
   
   public long Size 
   { get { return bufferSize; } }

   public void Dispose()
   {
      Dispose(true);
      GC.SuppressFinalize(this);
   }           

   protected virtual void Dispose(bool disposing)
   {
      if (disposed) return;

      // Dispose of managed resources here.
      if (disposing)
         safeHandle.Dispose();
      
      // Dispose of any unmanaged resources not wrapped in safe handles.
      
      disposed = true;
   }  
}
Imports Microsoft.Win32.SafeHandles
Imports System.IO

Public Class DisposableStreamResource : Implements IDisposable
   ' Define constants.
   Protected Const GENERIC_READ As UInteger = &H80000000ui
   Protected Const FILE_SHARE_READ As UInteger = &H0000000i
   Protected Const OPEN_EXISTING As UInteger = 3
   Protected Const FILE_ATTRIBUTE_NORMAL As UInteger = &H80
   Protected INVALID_HANDLE_VALUE As New IntPtr(-1)
   Private Const INVALID_FILE_SIZE As Integer = &HFFFFFFFF
   
   ' Define Windows APIs.
   Protected Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (
                                         lpFileName As String, dwDesiredAccess As UInt32, 
                                         dwShareMode As UInt32, lpSecurityAttributes As IntPtr, 
                                         dwCreationDisposition As UInt32, dwFlagsAndAttributes As UInt32, 
                                         hTemplateFile As IntPtr) As IntPtr
   Private Declare Function GetFileSize Lib "kernel32" (hFile As SafeFileHandle, 
                                                        ByRef lpFileSizeHigh As Integer) As Integer
    
   ' Define locals.
   Private disposed As Boolean = False
   Private safeHandle As SafeFileHandle 
   Private bufferSize As Long 
   Private upperWord As Integer
   
   Public Sub New(filename As String)
      If filename Is Nothing Then
         Throw New ArgumentNullException("The filename cannot be null.")
      Else If filename = ""
         Throw New ArgumentException("The filename cannot be an empty string.")
      End If
            
      Dim handle As IntPtr = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
                                        IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
                                        IntPtr.Zero)
      If handle <> INVALID_HANDLE_VALUE Then
         safeHandle = New SafeFileHandle(handle, True)
      Else
         Throw New FileNotFoundException(String.Format("Cannot open '{0}'", filename))
      End If
      
      ' Get file size.
      bufferSize = GetFileSize(safeHandle, upperWord) 
      If bufferSize = INVALID_FILE_SIZE Then
         bufferSize = -1
      Else If upperWord > 0 Then 
         bufferSize = (CLng(upperWord) << 32) + bufferSize
      End If     
   End Sub
   
   Public ReadOnly Property Size As Long
      Get
         Return bufferSize
      End Get
   End Property
   
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(True)
      GC.SuppressFinalize(Me)
   End Sub           

   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Exit Sub

      ' Dispose of managed resources here.
      If disposing Then
         safeHandle.Dispose()
      End If
      
      ' Dispose of any unmanaged resources not wrapped in safe handles.
      
      disposed = True
   End Sub  
End Class

使用安全控制代碼實作衍生類別的處置模式Using a safe handle to implement the dispose pattern for a derived class

下列範例將說明衍生類別 DisposableStreamResource2 的處置模式,該類別繼承自上述範例中顯示的 DisposableStreamResource 類別。The following example illustrates the dispose pattern for a derived class, DisposableStreamResource2, that inherits from the DisposableStreamResource class presented in the previous example. 這個類別會加入額外的方法 WriteFileInfo,並使用 SafeFileHandle 物件包裝可寫入檔案的控制代碼。The class adds an additional method, WriteFileInfo, and uses a SafeFileHandle object to wrap the handle of the writable file.

using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

public class DisposableStreamResource2 : DisposableStreamResource
{
   // Define additional constants.
   protected const uint GENERIC_WRITE = 0x40000000; 
   protected const uint OPEN_ALWAYS = 4;
   
   // Define additional APIs.
   [DllImport("kernel32.dll")]   
   protected static extern bool WriteFile(
                                SafeFileHandle safeHandle, string lpBuffer, 
                                int nNumberOfBytesToWrite, out int lpNumberOfBytesWritten,
                                IntPtr lpOverlapped);
   
   // Define locals.
   private bool disposed = false;
   private string filename;
   private bool created = false;
   private SafeFileHandle safeHandle;
   
   public DisposableStreamResource2(string filename) : base(filename)
   {
      this.filename = filename;
   }
   
   public void WriteFileInfo()
   { 
      if (! created) {
         IntPtr hFile = CreateFile(@".\FileInfo.txt", GENERIC_WRITE, 0, 
                                   IntPtr.Zero, OPEN_ALWAYS, 
                                   FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
         if (hFile != INVALID_HANDLE_VALUE)
            safeHandle = new SafeFileHandle(hFile, true);
         else
            throw new IOException("Unable to create output file.");

         created = true;
      }

      string output = String.Format("{0}: {1:N0} bytes\n", filename, Size);
      int bytesWritten;
      bool result = WriteFile(safeHandle, output, output.Length, out bytesWritten, IntPtr.Zero);                                     
   }

   protected override void Dispose(bool disposing)
   {
      if (disposed) return;
      
      // Release any managed resources here.
      if (disposing)
         safeHandle.Dispose();
      
      disposed = true;
      
      // Release any unmanaged resources not wrapped by safe handles here.
      
      // Call the base class implementation.
      base.Dispose(disposing);
   }
}
Imports Microsoft.Win32.SafeHandles
Imports System.IO

Public Class DisposableStreamResource2 : Inherits DisposableStreamResource
   ' Define additional constants.
   Protected Const GENERIC_WRITE As Integer = &H40000000 
   Protected Const OPEN_ALWAYS As Integer = 4
   
   ' Define additional APIs.
   Protected Declare Function WriteFile Lib "kernel32.dll" (
                              safeHandle As SafeFileHandle, lpBuffer As String, 
                              nNumberOfBytesToWrite As Integer, ByRef lpNumberOfBytesWritten As Integer,
                              lpOverlapped As Object) As Boolean
   
   ' Define locals.
   Private disposed As Boolean = False
   Private filename As String
   Private created As Boolean = False
   Private safeHandle As SafeFileHandle
   
   Public Sub New(filename As String)
      MyBase.New(filename)
      Me.filename = filename
   End Sub
   
   Public Sub WriteFileInfo() 
      If Not created Then
         Dim hFile As IntPtr = CreateFile(".\FileInfo.txt", GENERIC_WRITE, 0, 
                                          IntPtr.Zero, OPEN_ALWAYS, 
                                          FILE_ATTRIBUTE_NORMAL, IntPtr.Zero)
         If hFile <> INVALID_HANDLE_VALUE Then
            safeHandle = New SafeFileHandle(hFile, True)
         Else
            Throw New IOException("Unable to create output file.")
         End If
         created = True
      End If
      Dim output As String = String.Format("{0}: {1:N0} bytes {2}", filename, Size, 
                                           vbCrLf)
      WriteFile(safeHandle, output, output.Length, 0&, Nothing)                                     
   End Sub

   Protected Overloads Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Exit Sub
      
      ' Release any managed resources here.
      If disposing Then
         safeHandle.Dispose()
      End If
      
      disposed = True
      ' Release any unmanaged resources not wrapped by safe handles here.
      
      ' Call the base class implementation.
      MyBase.Dispose(disposing)
   End Sub
End Class

另請參閱See also