Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Der Garbage Collector (GC) der Common Language Runtime gibt den von verwalteten Objekten verwendeten Speicher frei. In der Regel implementieren Typen, die nicht verwaltete Ressourcen verwenden, die IDisposable oder IAsyncDisposable Schnittstelle, damit die nicht verwalteten Ressourcen freigegeben werden können. Wenn Sie mit der Verwendung eines Objekts fertig sind, das IDisposable implementiert, rufen Sie die Dispose- oder DisposeAsync-Implementierung des Objekts auf, um die Bereinigung explizit durchzuführen. Sie können dies auf eine von zwei Arten tun:
- Mit der C#
using-Anweisung oder -Deklaration (Usingin Visual Basic). - Durch Implementieren eines
try/finallyBlocks und Aufrufen der Dispose- oder DisposeAsync-Methode imfinally.
Von Bedeutung
Der GC entsorgt Ihre Objekte nicht, da er weder IDisposable.Dispose() noch IAsyncDisposable.DisposeAsync() kennt. Die GC weiß nur, ob ein Objekt abgeschlossen werden kann (d. h. es definiert eine Object.Finalize() Methode), und wenn der Finalizer des Objekts aufgerufen werden muss. Weitere Informationen finden Sie unter "Funktionsweise der Finalisierung". Weitere Details zur Implementierung Dispose und DisposeAsyncfinden Sie unter:
Objekte, die System.IDisposable oder System.IAsyncDisposable implementieren, sollten immer unabhängig vom Variablenbereich ordnungsgemäß gelöscht werden, sofern nicht ausdrücklich anders angegeben. Typen, die einen Finalizer definieren, um nicht verwaltete Ressourcen freizugeben, rufen GC.SuppressFinalize in der Regel von ihrer Dispose oder DisposeAsync Implementierung ab. Das Aufrufen von SuppressFinalize signalisiert dem GC, dass der Finalizer bereits ausgeführt wurde und das Objekt nicht zur Finalisierung freigegeben werden sollte.
Die using-Anweisung
Die using Anweisung in C# und die Using Anweisung in Visual Basic vereinfachen den Code, den Sie schreiben müssen, um ein Objekt zu bereinigen. Die using Anweisung ruft eine oder mehrere Ressourcen ab, führt die von Ihnen angegebenen Anweisungen aus und entfernt das Objekt automatisch. Die using Anweisung ist jedoch nur für Objekte nützlich, die im Rahmen der Methode verwendet werden, in der sie erstellt werden.
Im folgenden Beispiel wird die using Anweisung verwendet, um ein System.IO.StreamReader Objekt zu erstellen und freizugeben.
using System.IO;
class UsingStatement
{
static void Main()
{
var buffer = new char[50];
using (StreamReader streamReader = new("file1.txt"))
{
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
}
}
Imports System.IO
Module UsingStatement
Public Sub Main()
Dim buffer(49) As Char
Using streamReader As New StreamReader("File1.txt")
Dim charsRead As Integer
Do While streamReader.Peek() <> -1
charsRead = streamReader.Read(buffer, 0, buffer.Length)
'
' Process characters read.
'
Loop
End Using
End Sub
End Module
Eine using-Deklaration ist eine alternative Syntax, die verfügbar ist, wenn die Klammern entfernt werden und die Bereichsdefinition implizit ist.
using System.IO;
class UsingDeclaration
{
static void Main()
{
var buffer = new char[50];
using StreamReader streamReader = new("file1.txt");
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
}
Obwohl die StreamReader Klasse die IDisposable Schnittstelle implementiert, die angibt, dass sie eine nicht verwaltete Ressource verwendet, ruft das Beispiel die StreamReader.Dispose Methode nicht explizit auf. Wenn der C#- oder Visual Basic-Compiler auf die using Anweisung trifft, gibt er Zwischensprache (IL) aus, die dem folgenden Code entspricht, der explizit einen try/finally Block enthält.
using System.IO;
class TryFinallyGenerated
{
static void Main()
{
var buffer = new char[50];
StreamReader? streamReader = null;
try
{
streamReader = new StreamReader("file1.txt");
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
finally
{
// If non-null, call the object's Dispose method.
streamReader?.Dispose();
}
}
}
Imports System.IO
Module TryFinallyGenerated
Public Sub Main()
Dim buffer(49) As Char
Dim streamReader As New StreamReader("File1.txt")
Try
Dim charsRead As Integer
Do While streamReader.Peek() <> -1
charsRead = streamReader.Read(buffer, 0, buffer.Length)
'
' Process characters read.
'
Loop
Finally
If streamReader IsNot Nothing Then DirectCast(streamReader, IDisposable).Dispose()
End Try
End Sub
End Module
Mit der C# using -Anweisung können Sie auch mehrere Ressourcen in einer einzelnen Anweisung abrufen, die intern geschachtelten using Anweisungen entspricht. Im folgenden Beispiel werden zwei StreamReader Objekte instanziiert, um den Inhalt von zwei verschiedenen Dateien zu lesen.
using System.IO;
class SingleStatementMultiple
{
static void Main()
{
var buffer1 = new char[50];
var buffer2 = new char[50];
using StreamReader version1 = new("file1.txt"),
version2 = new("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-Block
Anstatt einen try/finally Block in eine using Anweisung umzuschließen, können Sie den try/finally Block direkt implementieren. Möglicherweise handelt es sich um Ihren persönlichen Codierungsstil, oder Sie möchten dies aus einem der folgenden Gründe tun:
- Um einen
catch-Block zum Behandeln von Ausnahmen in dentry-Block einzufügen. Andernfalls werden alle in derusing-Anweisung ausgelösten Ausnahmen nicht behandelt. - Um ein Objekt zu instanziieren, das IDisposable implementiert, dessen Gültigkeitsbereich nicht auf den Block beschränkt ist, in dem es deklariert wird.
Das folgende Beispiel ähnelt dem vorherigen Beispiel, mit der Ausnahme, dass ein try/catch/finally Block zum Instanziieren, Verwenden und Löschen eines StreamReader Objekts verwendet wird, und zum Behandeln von Ausnahmen, die vom StreamReader Konstruktor und dessen ReadToEnd Methode ausgelöst werden. Der Code im finally-Block überprüft, ob das Objekt, das IDisposable implementiert, nicht null ist, bevor es die Dispose-Methode aufruft. Wenn dies nicht getan wird, kann es zur Laufzeit zu einer NullReferenceException Ausnahme führen.
using System;
using System.Globalization;
using System.IO;
class TryExplicitCatchFinally
{
static void Main()
{
StreamReader? streamReader = null;
try
{
streamReader = new StreamReader("file1.txt");
string contents = streamReader.ReadToEnd();
var info = new StringInfo(contents);
Console.WriteLine($"The file has {info.LengthInTextElements} text elements.");
}
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
{
streamReader?.Dispose();
}
}
}
Imports System.Globalization
Imports System.IO
Module TryExplicitCatchFinally
Sub Main()
Dim streamReader As StreamReader = Nothing
Try
streamReader = New StreamReader("file1.txt")
Dim contents As String = streamReader.ReadToEnd()
Dim info As StringInfo = New StringInfo(contents)
Console.WriteLine($"The file has {info.LengthInTextElements} text elements.")
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 streamReader IsNot Nothing Then streamReader.Dispose()
End Try
End Sub
End Module
Sie können diesem grundlegenden Muster folgen, wenn Sie einen try/finally Block implementieren möchten oder müssen, da Ihre Programmiersprache keine using Anweisung unterstützt, aber direkte Aufrufe der Dispose Methode unterstützt.
IDisposable-Instanzmember
Wenn eine Klasse ein Instanzfeld oder eine Instanzeigenschaft besitzt und deren Typ IDisposable implementiert, sollte die Klasse auch IDisposable implementieren. Weitere Informationen finden Sie unter Implementieren eines kaskadierenden Dispose (Löschung).