Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Kolektor odpadów pamięci (GC) środowiska uruchomieniowego języka wspólnego odzyskuje pamięć używaną przez obiekty zarządzane. Zazwyczaj typy korzystające z zasobów niezarządzanych implementują IDisposable interfejs lub IAsyncDisposable , aby umożliwić odzyskanie niezarządzanych zasobów. Po zakończeniu korzystania z obiektu, który implementuje IDisposable, wywołujesz implementację Dispose lub DisposeAsync, aby przeprowadzić jawne czyszczenie. Można to zrobić na jeden z dwóch sposobów:
- Za pomocą instrukcji lub deklaracji języka C#
using
(Using
w Visual Basic). - Implementując blok
try/finally
i wywołując metodę Dispose lub DisposeAsync wfinally
.
Ważne
GC nie usuwa Twoich obiektów, ponieważ nie ma informacji o IDisposable.Dispose() lub IAsyncDisposable.DisposeAsync(). GC wie tylko, czy obiekt jest finalizowalny (czyli definiuje metodę Object.Finalize() ) i kiedy finalizator obiektu musi być wywoływany. Aby uzyskać więcej informacji, zobacz Jak działa finalizacja. Aby uzyskać dodatkowe informacje na temat implementacji Dispose
i DisposeAsync
, zobacz:
Obiekty, które implementują System.IDisposable lub System.IAsyncDisposable powinny być zawsze prawidłowo usuwane, niezależnie od zakresu zmiennych, chyba że określono inaczej. Typy definiujące finalizator do wydania niezarządzanych zasobów zwykle wywołują GC.SuppressFinalize w swojej Dispose
lub DisposeAsync
implementacji. Wywołanie SuppressFinalize wskazuje GC, że finalizator został już uruchomiony, a obiekt nie powinien być promowany do finalizacji.
Instrukcja "using"
Instrukcja using
w języku C# i Using
instrukcja w Visual Basic upraszczają kod, który należy napisać w celu oczyszczenia obiektu. Instrukcja using
uzyskuje co najmniej jeden zasób, wykonuje określone instrukcje i automatycznie usuwa obiekt. Jednak instrukcja using
jest przydatna tylko w przypadku obiektów używanych w zakresie metody, w której są konstruowane.
W poniższym przykładzie użyto instrukcji using
, aby utworzyć i zwolnić obiekt System.IO.StreamReader.
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
Deklaracjausing
jest alternatywną składnią dostępną, w której nawiasy klamrowe są usuwane, a zakres jest definiowany niejawnie.
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.
//
}
}
}
Mimo że klasa StreamReader implementuje interfejs IDisposable, który wskazuje, że używa niezarządzanego zasobu, przykład nie wywołuje jawnie metody StreamReader.Dispose. Gdy kompilator języka C# lub Visual Basic napotka instrukcję using
, emituje język pośredni (IL), który jest odpowiednikiem następującego kodu, który jawnie zawiera try/finally
blok.
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
Instrukcja C# using
umożliwia również uzyskanie wielu zasobów w jednej instrukcji, co wewnętrznie odpowiada zagnieżdżonym instrukcjom using
. Poniższy przykład tworzy dwa wystąpienia StreamReader obiektów do odczytania zawartości dwóch różnych plików.
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.
//
}
}
}
Spróbuj/na koniec blokuj
Zamiast obudowywać blok try/finally
instrukcją using
, możesz zdecydować się na implementację bloku try/finally
bezpośrednio. Może to być twój osobisty styl kodowania lub możesz to zrobić z jednego z następujących powodów:
- Aby włączyć blok
catch
do obsługi wyjątków, które są zgłaszane w blokutry
. W przeciwnym razie wszelkie wyjątki zgłoszone w instrukcjiusing
są nieobsługiwane. - Aby utworzyć wystąpienie obiektu, który implementuje IDisposable , którego zakres nie jest lokalny dla bloku, w którym jest zadeklarowany.
Poniższy przykład jest podobny do poprzedniego, z tą różnicą, że używa bloku try/catch/finally
do zainicjowania, używania i usuwania obiektu StreamReader, oraz do obsługi wszelkich wyjątków zgłaszanych przez konstruktor StreamReader i jego metodę ReadToEnd. Kod w bloku finally
sprawdza, czy obiekt, który implementuje IDisposable, nie jest null
przed wywołaniem metody Dispose. Niepowodzenie w wykonaniu tej czynności może spowodować wyjątek w NullReferenceException czasie działania.
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
Możesz postępować zgodnie z tym podstawowym wzorcem, jeśli zdecydujesz się zaimplementować lub musisz zaimplementować blok try/finally
, ponieważ język programowania nie obsługuje instrukcji using
, ale umożliwia bezpośrednie wywołania metody Dispose.
Członkowie instancji IDisposable
Jeśli klasa jest właścicielem pola lub właściwości wystąpienia, a jej typ implementuje IDisposable, klasa powinna również zaimplementować IDisposable. Aby uzyskać więcej informacji, zobacz Implementowanie usuwania kaskadowego.