Objecten gebruiken die IDisposable implementeren
De garbagecollector (GC) van de Common Language Runtime maakt het geheugen vrij dat wordt gebruikt door beheerde objecten. Normaal gesproken implementeren typen die onbeheerde resources gebruiken de IDisposable of IAsyncDisposable interface om de onbeheerde resources vrij te maken. Wanneer u klaar bent met het gebruik van een object dat wordt geïmplementeerdIDisposable, roept u de of DisposeAsync implementatie van Dispose het object aan om expliciet opschoning uit te voeren. U kunt dit op twee manieren doen:
- Met de C#
using
-instructie of -declaratie (Using
in Visual Basic). - Door een
try/finally
blok te implementeren en de Dispose of DisposeAsync methode in definally
.
Belangrijk
De GC gooit uw objecten niet weg, omdat het geen kennis heeft van IDisposable.Dispose() of IAsyncDisposable.DisposeAsync(). De GC weet alleen of een object kan worden voltooid (dat wil zeggen, er wordt een Object.Finalize() methode gedefinieerd) en wanneer de finalizer van het object moet worden aangeroepen. Zie Hoe voltooien werkt voor meer informatie. Zie voor meer informatie over het implementeren Dispose
en DisposeAsync
bekijken van:
Objecten die moeten worden geïmplementeerd System.IDisposable of System.IAsyncDisposable altijd correct moeten worden verwijderd, ongeacht het bereik van variabelen, tenzij anders expliciet wordt vermeld. Typen die een finalizer definiëren om onbeheerde resources vrij te geven, roepen GC.SuppressFinalize meestal aan vanuit hun Dispose
of DisposeAsync
implementatie. Aanroepen SuppressFinalize geeft aan dat de GC al is uitgevoerd en dat het object niet mag worden gepromoveerd voor voltooien.
De using-instructie
De using
instructie in C# en de Using
instructie in Visual Basic vereenvoudigen de code die u moet schrijven om een object op te ruimen. De using
instructie verkrijgt een of meer resources, voert de instructies uit die u opgeeft en verwijdert automatisch het object. De using
instructie is echter alleen nuttig voor objecten die worden gebruikt binnen het bereik van de methode waarin ze worden samengesteld.
In het volgende voorbeeld wordt de using
instructie gebruikt om een System.IO.StreamReader object te maken en vrij te geven.
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
Een using
declaratie is een alternatieve syntaxis die beschikbaar is wanneer de accolades worden verwijderd en het bereik impliciet is.
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.
//
}
}
}
Hoewel de StreamReader klasse de IDisposable interface implementeert, wat aangeeft dat er een onbeheerde resource wordt gebruikt, wordt de StreamReader.Dispose methode niet expliciet aangeroepen in het voorbeeld. Wanneer de C# of Visual Basic-compiler de using
instructie tegenkomt, wordt er een tussenliggende taal (IL) verzonden die gelijk is aan de volgende code die expliciet een try/finally
blok bevat.
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
Met de C# using
-instructie kunt u ook meerdere resources in één instructie verkrijgen, wat intern gelijk is aan geneste using
instructies. In het volgende voorbeeld worden twee StreamReader objecten geïnstitueert om de inhoud van twee verschillende bestanden te lezen.
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.
//
}
}
}
Probeer/ten slotte blokkeren
In plaats van een try/finally
blok in een using
instructie te verpakken, kunt u ervoor kiezen om het try/finally
blok rechtstreeks te implementeren. Het kan uw persoonlijke coderingsstijl zijn of u wilt dit om een van de volgende redenen doen:
- Als u een
catch
blok wilt opnemen voor het verwerken van uitzonderingen die in hettry
blok zijn opgetreden. Anders worden eventuele uitzonderingen die in deusing
instructie worden gegenereerd, niet verwerkt. - Als u een object wilt instantiëren dat implementeert IDisposable waarvan het bereik niet lokaal is voor het blok waarin het wordt gedeclareerd.
Het volgende voorbeeld is vergelijkbaar met het vorige voorbeeld, behalve dat er een blok wordt gebruikt om een try/catch/finally
StreamReader object te instantiëren, gebruiken en verwijderen, en om eventuele uitzonderingen te verwerken die zijn gegenereerd door de constructor en ReadToEnd de StreamReader bijbehorende methode. De code in het finally
blok controleert of het object dat wordt geïmplementeerd IDisposable niet null
voordat de Dispose methode wordt aangeroepen. Als u dit niet doet, kan dit leiden tot een NullReferenceException uitzondering tijdens runtime.
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
U kunt dit basispatroon volgen als u ervoor kiest om een try/finally
blok te implementeren of te implementeren, omdat uw programmeertaal geen ondersteuning biedt voor een using
instructie, maar wel directe aanroepen naar de Dispose methode toestaat.
Leden van IDisposable-exemplaren
Als een klasse eigenaar is van een exemplaarveld of eigenschap en het bijbehorende type implementeert IDisposable, moet de klasse ook implementeren IDisposable. Zie Een trapsgewijs verwijderen implementeren voor meer informatie.