使用實作 IDisposable 的物件Using objects that implement IDisposable

通用語言執行平台的記憶體回收行程會回收受控物件所使用的記憶體,但是使用非受控資源的類型會實作 IDisposable 介面,以允許回收配置給這些非受控資源的記憶體。The common language runtime's garbage collector reclaims the memory used by managed objects, but types that use unmanaged resources implement the IDisposable interface to allow the memory allocated to these unmanaged resources to be reclaimed. 實作 IDisposable 的物件使用完畢時,您應呼叫物件的 IDisposable.Dispose 實作。When you finish using an object that implements IDisposable, you should call the object's IDisposable.Dispose implementation. 您可以使用下列其中一種做法:You can do this in one of two ways:

  • 使用 C# using 陳述式或 Visual Basic Using 陳述式。With the C# using statement or the Visual Basic Using statement.

  • 藉由實作 try/finally 區塊。By implementing a try/finally block.

using 陳述式The using statement

C# 中的 using 陳述式和 Visual Basic 中的 Using 陳述式可簡化建立和清除物件所必須撰寫的程式碼。The using statement in C# and the Using statement in Visual Basic simplify the code that you must write to create and clean up an object. using 陳述式會取得一項或多項資源、執行您指定的陳述式,然後自動處置該物件。The using statement obtains one or more resources, executes the statements that you specify, and automatically disposes of the object. 不過,using 陳述式只對建構物件的方法範圍內所使用的物件有其實用之處。However, the using statement is useful only for objects that are used within the scope of the method in which they are constructed.

下列範例會使用 using 陳述式建立和發行 System.IO.StreamReader 物件。The following example uses the using statement to create and release a System.IO.StreamReader object.

using System;
using System.IO;

public class Example
{
   public static void Main()
   {
      Char[] buffer = new Char[50];
      using (StreamReader s = new StreamReader("File1.txt")) {
         int charsRead = 0;
         while (s.Peek() != -1) {
            charsRead = s.Read(buffer, 0, buffer.Length);
            //
            // Process characters read.
            //   
         }
      }

   }
}
Imports System.IO

Module Example
   Public Sub Main()
      Dim buffer(49) As Char
      Using s As New StreamReader("File1.txt")
         Dim charsRead As Integer
         Do While s.Peek() <> -1
            charsRead = s.Read(buffer, 0, buffer.Length)         
            ' 
            ' Process characters read.
            '
         Loop
      End Using
   End Sub
End Module

請注意,雖然 StreamReader 類別會實作 IDisposable 介面,指出它使用的是 Unmanaged 資源,但是這個範例並不會明確呼叫 StreamReader.Dispose 方法。Note that although the StreamReader class implements the IDisposable interface, which indicates that it uses an unmanaged resource, the example doesn't explicitly call the StreamReader.Dispose method. 當 C# 或 Visual Basic 編譯器遇到 using 陳述式時,會發出相當於下列明確包含 try/finally 區塊之程式碼的中繼語言 (IL)。When the C# or Visual Basic compiler encounters the using statement, it emits intermediate language (IL) that is equivalent to the following code that explicitly contains a try/finally block.

using System;
using System.IO;

public class Example
{
   public static void Main()
   {
      Char[] buffer = new Char[50];
      {
         StreamReader s = new StreamReader("File1.txt"); 
         try {
            int charsRead = 0;
            while (s.Peek() != -1) {
               charsRead = s.Read(buffer, 0, buffer.Length);
               //
               // Process characters read.
               //   
            }
         }
         finally {
            if (s != null)
               ((IDisposable)s).Dispose();     
         }       
      }
   }
}
Imports System.IO

Module Example
   Public Sub Main()
      Dim buffer(49) As Char
''      Dim s As New StreamReader("File1.txt")
With s As New StreamReader("File1.txt")
      Try
         Dim charsRead As Integer
         Do While s.Peek() <> -1
            charsRead = s.Read(buffer, 0, buffer.Length)         
            ' 
            ' Process characters read.
            '
         Loop
      Finally
         If s IsNot Nothing Then DirectCast(s, IDisposable).Dispose()
      End Try
End With
   End Sub
End Module

C# using 陳述式還可讓您以單一陳述式取得多項資源,其內部相當於巢狀的 using 陳述式。The C# using statement also allows you to acquire multiple resources in a single statement, which is internally equivalent to nested using statements. 下列範例會將兩個 StreamReader 物件具現化,以便讀取兩個不同檔案的內容。The following example instantiates two StreamReader objects to read the contents of two different files.

using System;
using System.IO;

public class Example
{
   public static void Main()
   {
      Char[] buffer1 = new Char[50], buffer2 = new Char[50];
      
      using (StreamReader version1 = new StreamReader("file1.txt"),
                          version2 = new StreamReader("file2.txt")) {
         int charsRead1, charsRead2 = 0;
         while (version1.Peek() != -1 && version2.Peek() != -1) {
            charsRead1 = version1.Read(buffer1, 0, buffer1.Length);
            charsRead2 = version2.Read(buffer2, 0, buffer2.Length);
            //
            // Process characters read.
            //
         }
      }
   }
}

Try/finally 區塊Try/finally block

您可以選擇直接實作 try/finally 區塊,而不將 try/finally 區塊包裝在 using 陳述式中。Instead of wrapping a try/finally block in a using statement, you may choose to implement the try/finally block directly. 這可成為您的個人編碼風格,也可能基於下列其中一個原因而這樣做:This may be your personal coding style, or you might want to do this for one of the following reasons:

  • 包含 catch 區塊以處理 try 區塊中擲回的任何例外狀況。To include a catch block to handle any exceptions thrown in the try block. 否則,當 try/catch 區塊不存在時,using 陳述式擲回的所有例外狀況都會是未處理,就連 using 區塊中擲回的任何例外狀況也一樣。Otherwise, any exceptions thrown by the using statement are unhandled, as are any exceptions thrown within the using block if a try/catch block isn't present.

  • 若要將實作 IDisposable 且範圍對於物件宣告所在區塊並非區域的物件具現化。To instantiate an object that implements IDisposable whose scope is not local to the block within which it is declared.

下列範例類似上述範例,不過它會使用 try/catch/finally 區塊具現化、使用和處置 StreamReader 物件,以及處理 StreamReader 建構函式和其 ReadToEnd 方法擲回的所有例外狀況。The following example is similar to the previous example, except that it uses a try/catch/finally block to instantiate, use, and dispose of a StreamReader object, and to handle any exceptions thrown by the StreamReader constructor and its ReadToEnd method. 請注意,在 finally 中的程式碼會先確認實作 IDisposable 的物件不是 null,再呼叫 Dispose 方法。Note that the code in the finally block checks that the object that implements IDisposable isn't null before it calls the Dispose method. 若未這樣做,可能導致執行階段產生 NullReferenceException 例外狀況。Failure to do this can result in a NullReferenceException exception at run time.

using System;
using System.Globalization;
using System.IO;

public class Example
{
   public static void Main()
   {
      StreamReader sr = null;
      try {
         sr = new StreamReader("file1.txt");
         String contents = sr.ReadToEnd();
         Console.WriteLine("The file has {0} text elements.", 
                           new StringInfo(contents).LengthInTextElements);    
      }      
      catch (FileNotFoundException) {
         Console.WriteLine("The file cannot be found.");
      }   
      catch (IOException) {
         Console.WriteLine("An I/O error has occurred.");
      }
      catch (OutOfMemoryException) {
         Console.WriteLine("There is insufficient memory to read the file.");   
      }
      finally {
         if (sr != null) sr.Dispose();     
      }
   }
}
Imports System.Globalization
Imports System.IO

Module Example
   Public Sub Main()
      Dim sr As StreamReader = Nothing
      Try 
         sr = New StreamReader("file1.txt")
         Dim contents As String = sr.ReadToEnd()
         Console.WriteLine("The file has {0} text elements.", 
                           New StringInfo(contents).LengthInTextElements)    
      Catch e As FileNotFoundException
         Console.WriteLine("The file cannot be found.")
      Catch e As IOException
         Console.WriteLine("An I/O error has occurred.")
      Catch e As OutOfMemoryException
         Console.WriteLine("There is insufficient memory to read the file.")   
      Finally 
         If sr IsNot Nothing Then sr.Dispose()     
      End Try
   End Sub
End Module

如果您的程式語言不支援 using 陳述式,但是允許直接呼叫 Dispose 方法,而使得您選擇實作或必須實作 try/finally 區塊,則可以遵循這個基本模式。You can follow this basic pattern if you choose to implement or must implement a try/finally block, because your programming language doesn't support a using statement but does allow direct calls to the Dispose method.

另請參閱See also