Menggunakan objek yang menerapkan IDisposable
Pengumpul sampah (GC) runtime bahasa umum mengklaim kembali memori yang digunakan oleh objek terkelola. Biasanya, jenis yang menggunakan sumber daya yang tidak dikelola mengimplementasikan IDisposable antarmuka atau IAsyncDisposable untuk memungkinkan sumber daya yang tidak dikelola diklaim kembali. Setelah selesai menggunakan objek yang mengimplementasikan IDisposable, Anda memanggil objek Dispose atau DisposeAsync implementasi untuk melakukan pembersihan secara eksplisit. Anda dapat melakukannya dengan salah satu dari dua cara ini:
- Dengan pernyataan atau deklarasi C#
using
(Using
dalam Visual Basic). - Dengan menerapkan blok
try/finally
, dan memanggil metode Dispose atau DisposeAsync difinally
.
Penting
GC tidak membuang objek Anda, karena tidak memiliki pengetahuan tentang IDisposable.Dispose() atau IAsyncDisposable.DisposeAsync(). GC hanya tahu apakah objek dapat diselesaikan (yaitu, mendefinisikan metode Object.Finalize()), dan kapan finalizer objek perlu dipanggil. Untuk informasi selengkapnya, lihat Cara kerja finalisasi. Untuk detail tambahan tentang penerapan Dispose
dan DisposeAsync
, lihat:
Objek yang mengimplementasikan System.IDisposable atau System.IAsyncDisposable harus selalu dibuang dengan benar, terlepas dari cakupan variabel, kecuali dinyatakan secara eksplisit. Jenis yang menentukan finalizer untuk merilis sumber daya yang tidak dikelola biasanya memanggil GC.SuppressFinalize dari implementasi Dispose
atau DisposeAsync
mereka. Panggilan SuppressFinalize menunjukkan kepada GC bahwa finalizer telah dijalankan dan objek tidak boleh dipromosikan untuk finalisasi.
Pernyataan using
Pernyataan using
dalam C# dan pernyataan Using
dalam Visual Basic menyederhturunanan kode yang harus Anda tulis untuk membersihkan objek. Pernyataan memperoleh using
satu atau beberapa sumber daya, menjalankan pernyataan yang Anda tentukan, dan secara otomatis membuang objek. Namun, pernyataan using
ini hanya berguna untuk objek yang digunakan dalam cakupan metode di mana mereka dibangun.
Contoh berikut menggunakan pernyataan using
untuk membuat dan merilis objek 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
using
Deklarasi adalah sintaks alternatif yang tersedia di mana kurung kurawal dihapus, dan cakupannya implisit.
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.
//
}
}
}
Meski kelas StreamReader mengimplementasikan antarmuka IDisposable, yang menunjukkan bahwa ini menggunakan sumber daya yang tidak dikelola, contohnya tidak secara eksplisit memanggil metode StreamReader.Dispose. Saat pengompilasi C# atau Visual Basic menemukan pernyataan using
, itu memancarkan bahasa perantara (IL) yang setara dengan kode berikut yang secara eksplisit berisi blok try/finally
.
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
Pernyataan C# using
juga memungkinkan Anda memperoleh beberapa sumber daya dalam satu pernyataan, yang secara internal setara dengan pernyataan berlapis using
. Contoh berikut membuat instans dua StreamReader objek untuk membaca konten dua file yang berbeda.
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.
//
}
}
}
Blok try/finally
Alih-alih membungkus try/finally
blok dalam using
pernyataan, Anda dapat memilih untuk mengimplementasikan blok secara try/finally
langsung. Ini mungkin gaya pengkodian pribadi Anda, atau Anda mungkin ingin melakukan ini karena salah satu alasan berikut:
- Untuk menyertakan
catch
blok untuk menangani pengecualian yang dilemparkan ditry
blok. Jika tidak, pengecualian apa pun yang dilemparkanusing
dalam pernyataan tidak tertangani. - Untuk membuat instans IDisposable objek yang mengimplementasikan cakupannya tidak lokal ke blok tempat objek dideklarasikan.
Contoh berikut mirip dengan contoh sebelumnya, kecuali bahwa ia menggunakan blok untuk membuat instans try/catch/finally
, menggunakan, dan membuang StreamReader objek, dan untuk menangani pengecualian apa pun yang dilemparkan oleh StreamReader konstruktor dan metodenya ReadToEnd . Kode dalam finally
blok memeriksa bahwa objek yang menerapkan IDisposable tidak null
sebelum memanggil Dispose metode. Kegagalan untuk melakukan ini dapat mengakibatkan NullReferenceException pengecualian pada durasi.
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
Anda dapat mengikuti pola dasar ini jika Anda memilih untuk menerapkan atau harus menerapkan try/finally
blok, karena bahasa pemrograman Anda tidak mendukung using
pernyataan tetapi mengizinkan panggilan langsung ke metode .Dispose
Anggota instans IDisposable
Jika kelas memiliki bidang atau properti instans IDisposabledan jenisnya mengimplementasikan , kelas juga harus menerapkan IDisposable. Untuk informasi selengkapnya, lihat Menerapkan pembuangan kaskade.