Verwenden von Objekten, die IDisposable implementierenUsing objects that implement IDisposable

Der Garbage Collector der Common Language Runtime gibt den Speicher frei, der von verwalteten Objekten verwendet wird. Typen jedoch, die nicht verwaltete Ressourcen verwenden, implementieren die IDisposable-Schnittstelle, damit der Speicher, der diesen nicht verwalteten Ressourcen zugeordnet ist, freigegeben werden kann.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. Wenn Sie ein Objekt, das IDisposable implementiert, nicht mehr verwenden, sollten Sie die IDisposable.Dispose-Implementierung des Objekts aufrufen.When you finish using an object that implements IDisposable, you should call the object's IDisposable.Dispose implementation. Dazu haben Sie zwei Möglichkeiten:You can do this in one of two ways:

  • Verwenden der using-Anweisung in C# oder der Using-Anweisung in Visual Basic.With the C# using statement or the Visual Basic Using statement.

  • Implementieren eines try/finally-Blocks.By implementing a try/finally block.

Die using-AnweisungThe using statement

Die using-Anweisung in C# und die Using-Anweisung in Visual Basic vereinfachen den Code, den Sie schreiben müssen, um ein Objekt zu erstellen und zu bereinigen.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. Die using-Anweisung ruft eine oder mehrere Ressourcen ab, führt die von Ihnen angegebenen Anweisungen aus und verwirft dann das Objekt automatisch.The using statement obtains one or more resources, executes the statements that you specify, and automatically disposes of the object. Die using-Anweisung ist jedoch nur hilfreich bei Objekten, die im Bereich der Methode verwendet werden, in der sie erstellt werden.However, the using statement is useful only for objects that are used within the scope of the method in which they are constructed.

Im folgenden Beispiel wird die using-Anweisung verwendet, um ein System.IO.StreamReader-Objekt zu erstellen und freizugeben.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

Beachten Sie Folgendes: Obwohl die StreamReader-Klasse die IDisposable-Schnittstelle implementiert, die angibt, dass sie eine nicht verwaltete Ressource verwendet, wird in dem Beispiel nicht explizit die StreamReader.Dispose-Methode aufgerufen.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. Wenn der C#- oder Visual Basic-Compiler die using-Anweisung findet, gibt er Zwischensprache (Intermediate Language, IL) aus, die dem folgenden Code entspricht, der explizit einen try/finally-Block enthält.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

Mit der using-Anweisung in C# können Sie auch mehrere Ressourcen in einer einzigen Anweisung abrufen. Intern entspricht dies geschachtelten using-Anweisungen.The C# using statement also allows you to acquire multiple resources in a single statement, which is internally equivalent to nested using statements. Im folgenden Beispiel werden zwei StreamReader-Objekte instanziiert, um den Inhalt von zwei verschiedenen Dateien zu lesen.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-BlockTry/finally block

Anstatt einen try/finally-Block in einer using-Anweisung zu umschließen, haben Sie die Möglichkeit, den try/finally-Block direkt zu implementieren.Instead of wrapping a try/finally block in a using statement, you may choose to implement the try/finally block directly. Dies kann Ihr persönlicher Codierungsstil sein, oder Sie möchten dies eventuell aus einem der folgenden Gründe durchführen:This may be your personal coding style, or you might want to do this for one of the following reasons:

  • Um einen catch-Block einzufügen, um im try-Block ausgelöste Ausnahmen zu behandeln.To include a catch block to handle any exceptions thrown in the try block. Andernfalls bleiben alle Ausnahmen, die von der using-Anweisung ausgelöst werden, unbehandelt, so wie Ausnahmen, die innerhalb des using-Blocks ausgelöst werden, wenn kein try/catch-Block vorhanden ist.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.

  • Um ein Objekt zu instanziieren, das IDisposable implementiert, dessen Bereich für den Block, in dem es deklariert ist, nicht lokal ist.To instantiate an object that implements IDisposable whose scope is not local to the block within which it is declared.

Das folgende Beispiel ähnelt dem vorhergehenden, es wird jedoch ein try/catch/finally-Block verwendet, um ein StreamReader-Objekt zu instanziieren, zu verwenden und zu verwerfen, und um alle Ausnahmen zu behandeln, die von dem StreamReader-Konstruktor und dessen ReadToEnd-Methode ausgelöst werden.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. Beachten Sie, dass der Code im finally-Block überprüft, ob das Objekt, das IDisposable implementiert, nicht null ist, bevor die Dispose-Methode aufgerufen wird.Note that the code in the finally block checks that the object that implements IDisposable isn't null before it calls the Dispose method. Wird dies nicht ausgeführt, kann es zu einer NullReferenceException-Ausnahme zur Laufzeit kommen.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

Sie können dieses grundlegende Muster beibehalten, wenn Sie einen try/finally-Block implementieren möchten oder müssen, da Ihre Programmiersprache eine using-Anweisung nicht unterstützt, jedoch direkte Aufrufe der Dispose-Methode erlaubt.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.

Siehe auchSee also