Antarmuka System.IDisposable
Artikel ini menyediakan keterangan tambahan untuk dokumentasi referensi untuk API ini.
Penggunaan utama IDisposable antarmuka adalah untuk merilis sumber daya yang tidak dikelola. Pengumpul sampah secara otomatis melepaskan memori yang dialokasikan ke objek terkelola ketika objek tersebut tidak lagi digunakan. Namun, tidak mungkin untuk memprediksi kapan pengumpulan sampah akan terjadi. Selain itu, pengumpul sampah tidak memiliki pengetahuan tentang sumber daya yang tidak dikelola seperti handel jendela, atau membuka file dan aliran.
Dispose Gunakan metode antarmuka ini untuk secara eksplisit merilis sumber daya yang tidak dikelola bersama dengan pengumpul sampah. Konsumen objek dapat memanggil metode ini ketika objek tidak lagi diperlukan.
Peringatan
Ini adalah perubahan yang melanggar untuk menambahkan IDisposable antarmuka ke kelas yang ada. Karena konsumen yang sudah ada sebelumnya dari jenis Anda tidak dapat memanggil Dispose, Anda tidak dapat yakin bahwa sumber daya yang tidak dikelola yang dipegang oleh jenis Anda akan dirilis.
IDisposable.Dispose Karena implementasi dipanggil oleh konsumen jenis ketika sumber daya yang dimiliki oleh instans tidak lagi diperlukan, Anda harus membungkus objek terkelola dalam SafeHandle (alternatif yang direkomendasikan), atau Anda harus mengambil alih Object.Finalize untuk membebaskan sumber daya yang tidak dikelola jika konsumen lupa memanggil Dispose.
Penting
Dalam .NET Framework, pengkompilasi C++ mendukung pembuangan deterministik sumber daya dan tidak mengizinkan implementasi Dispose langsung metode.
Untuk diskusi terperinci tentang bagaimana antarmuka ini dan Object.Finalize metode ini digunakan, lihat Topik Pengumpulan sampah dan Menerapkan Metode Buang.
Menggunakan objek yang mengimplementasikan IDisposable
Jika aplikasi Anda hanya menggunakan objek yang mengimplementasikan IDisposable antarmuka, Anda harus memanggil implementasi objek IDisposable.Dispose saat Anda selesai menggunakannya. Bergantung pada bahasa pemrograman Anda, Anda dapat melakukan ini dengan salah satu dari dua cara:
- Dengan menggunakan konstruksi bahasa seperti
using
pernyataan dalam C# dan Visual Basic, danuse
pernyataan atauusing
fungsi dalam F#. - Dengan membungkus panggilan ke IDisposable.Dispose implementasi dalam blok
try
/finally
.
Catatan
Dokumentasi untuk jenis yang menerapkan IDisposable perhatikan bahwa fakta dan menyertakan pengingat untuk memanggil implementasinya Dispose .
Pernyataan C#, F#, dan Visual Basic Menggunakan
Jika bahasa Anda mendukung konstruksi seperti pernyataan penggunaan di C#, pernyataan Penggunaan di Visual Basic, atau pernyataan penggunaan di F#, Anda dapat menggunakannya alih-alih secara eksplisit memanggil IDisposable.Dispose diri Anda sendiri. Contoh berikut menggunakan pendekatan ini dalam menentukan WordCount
kelas yang mempertahankan informasi tentang file dan jumlah kata di dalamnya.
using System;
using System.IO;
using System.Text.RegularExpressions;
public class WordCount
{
private String filename = String.Empty;
private int nWords = 0;
private String pattern = @"\b\w+\b";
public WordCount(string filename)
{
if (!File.Exists(filename))
throw new FileNotFoundException("The file does not exist.");
this.filename = filename;
string txt = String.Empty;
using (StreamReader sr = new StreamReader(filename))
{
txt = sr.ReadToEnd();
}
nWords = Regex.Matches(txt, pattern).Count;
}
public string FullName
{ get { return filename; } }
public string Name
{ get { return Path.GetFileName(filename); } }
public int Count
{ get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions
type WordCount(filename) =
let txt =
if File.Exists filename |> not then
raise (FileNotFoundException "The file does not exist.")
use sr = new StreamReader(filename)
sr.ReadToEnd()
let pattern = @"\b\w+\b"
let nWords = Regex.Matches(txt, pattern).Count
member _.FullName = filename
member _.Name = Path.GetFileName filename
member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions
Public Class WordCount
Private filename As String
Private nWords As Integer
Private pattern As String = "\b\w+\b"
Public Sub New(filename As String)
If Not File.Exists(filename) Then
Throw New FileNotFoundException("The file does not exist.")
End If
Me.filename = filename
Dim txt As String = String.Empty
Using sr As New StreamReader(filename)
txt = sr.ReadToEnd()
End Using
nWords = Regex.Matches(txt, pattern).Count
End Sub
Public ReadOnly Property FullName As String
Get
Return filename
End Get
End Property
Public ReadOnly Property Name As String
Get
Return Path.GetFileName(filename)
End Get
End Property
Public ReadOnly Property Count As Integer
Get
Return nWords
End Get
End Property
End Class
Pernyataan using
(use
ekspresi dalam F#) sebenarnya adalah kenyamanan sinaksis. Pada waktu kompilasi, pengkompilasi bahasa mengimplementasikan bahasa perantara (IL) untuk blok try
/finally
.
Untuk informasi selengkapnya tentang pernyataan, using
lihat menggunakan Pernyataan atau menggunakan topik Pernyataan .
Blok Coba/Akhirnya
Jika bahasa pemrograman Anda tidak mendukung konstruksi seperti using
pernyataan di C# atau Visual Basic, atau use
pernyataan di F#, atau jika Anda lebih suka tidak menggunakannya, Anda dapat memanggil IDisposable.Dispose implementasi dari finally
blok try
/finally
pernyataan. Contoh berikut mengganti blok using
dalam contoh sebelumnya dengan try
/finally
blok.
using System;
using System.IO;
using System.Text.RegularExpressions;
public class WordCount2
{
private String filename = String.Empty;
private int nWords = 0;
private String pattern = @"\b\w+\b";
public WordCount2(string filename)
{
if (!File.Exists(filename))
throw new FileNotFoundException("The file does not exist.");
this.filename = filename;
string txt = String.Empty;
StreamReader? sr = null;
try
{
sr = new StreamReader(filename);
txt = sr.ReadToEnd();
}
finally
{
if (sr != null) sr.Dispose();
}
nWords = Regex.Matches(txt, pattern).Count;
}
public string FullName
{ get { return filename; } }
public string Name
{ get { return Path.GetFileName(filename); } }
public int Count
{ get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions
type WordCount2(filename) =
let txt =
if File.Exists filename |> not then
raise (FileNotFoundException "The file does not exist.")
let sr = new StreamReader(filename)
try
sr.ReadToEnd()
finally
sr.Dispose()
let pattern = @"\b\w+\b"
let nWords = Regex.Matches(txt, pattern).Count
member _.FullName = filename
member _.Name = Path.GetFileName filename
member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions
Public Class WordCount2
Private filename As String
Private nWords As Integer
Private pattern As String = "\b\w+\b"
Public Sub New(filename As String)
If Not File.Exists(filename) Then
Throw New FileNotFoundException("The file does not exist.")
End If
Me.filename = filename
Dim txt As String = String.Empty
Dim sr As StreamReader = Nothing
Try
sr = New StreamReader(filename)
txt = sr.ReadToEnd()
Finally
If sr IsNot Nothing Then sr.Dispose()
End Try
nWords = Regex.Matches(txt, pattern).Count
End Sub
Public ReadOnly Property FullName As String
Get
Return filename
End Get
End Property
Public ReadOnly Property Name As String
Get
Return Path.GetFileName(filename)
End Get
End Property
Public ReadOnly Property Count As Integer
Get
Return nWords
End Get
End Property
End Class
Untuk informasi selengkapnya tentang pola, try
/finally
lihat Coba... Menangkap... Pernyataan Terakhir, coba akhirnya, coba... akhirnya Ekspresi, atau coba-akhirnya Pernyataan.
Menerapkan IDisposable
Anda harus menerapkan IDisposable jika jenis Anda menggunakan sumber daya yang tidak dikelola secara langsung atau jika Anda ingin menggunakan sumber daya sekali pakai sendiri. Konsumen jenis Anda dapat memanggil implementasi Anda IDisposable.Dispose ke sumber daya gratis ketika instans tidak lagi diperlukan. Untuk menangani kasus di mana mereka gagal memanggil Dispose, Anda harus menggunakan kelas yang berasal dari SafeHandle untuk membungkus sumber daya yang tidak dikelola, atau Anda harus mengambil alih Object.Finalize metode untuk jenis referensi. Dalam kedua kasus, Anda menggunakan Dispose metode untuk melakukan pembersihan apa pun yang diperlukan setelah menggunakan sumber daya yang tidak dikelola, seperti membebaskan, melepaskan, atau mengatur ulang sumber daya yang tidak dikelola. Untuk informasi selengkapnya tentang menerapkan IDisposable.Dispose, lihat metode Buang (bool) kelebihan beban.
Penting
Jika Anda mendefinisikan kelas dasar yang menggunakan sumber daya yang tidak dikelola dan yang memiliki, atau kemungkinan memiliki, subkelas yang harus dibuang, Anda harus menerapkan IDisposable.Dispose metode dan memberikan kelebihan kedua dari Dispose
, seperti yang dibahas di bagian berikutnya.
IDisposable dan hierarki warisan
Kelas dasar dengan subkelas yang harus sekali pakai harus diimplementasikan IDisposable sebagai berikut. Anda harus menggunakan pola ini setiap kali Anda menerapkan IDisposable pada jenis apa pun yang tidak sealed
(NotInheritable
di Visual Basic).
- Ini harus menyediakan satu metode publik, non-virtual Dispose() dan metode virtual
Dispose(Boolean disposing)
yang dilindungi. - Metode Dispose() harus memanggil
Dispose(true)
dan harus menekan finalisasi untuk performa. - Jenis dasar tidak boleh menyertakan finalizer apa pun.
Fragmen kode berikut mencerminkan pola buang untuk kelas dasar. Ini mengasumsikan bahwa jenis Anda tidak mengambil Object.Finalize alih metode .
using System;
using System.IO;
using System.Runtime.InteropServices;
class BaseClass1 : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a FileStream instance.
FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
fs.Dispose();
// Free any other managed objects here.
//
}
disposed = true;
}
}
open System
open System.IO
type BaseClass1() =
// Flag: Has Dispose already been called?
let mutable disposed = false
// Instantiate a FileStream instance.
let fs = new FileStream("test.txt", FileMode.OpenOrCreate)
interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this
// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
fs.Dispose()
// Free any other managed objects here.
disposed <- true
Imports System.IO
Imports System.Runtime.InteropServices
Class BaseClass1 : Implements IDisposable
' Flag: Has Dispose already been called?
Dim disposed As Boolean = False
' Instantiate a FileStream instance.
Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Return
If disposing Then
fs.Dispose()
' Free any other managed objects here.
'
End If
disposed = True
End Sub
End Class
Jika Anda mengambil alih metode , Object.Finalize kelas Anda harus menerapkan pola berikut.
using System;
class BaseClass2 : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
}
~BaseClass2()
{
Dispose(disposing: false);
}
}
open System
type BaseClass2() =
// Flag: Has Dispose already been called?
let mutable disposed = false
interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this
// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
// Free any other managed objects here.
()
// Free any unmanaged objects here.
disposed <- true
override this.Finalize() =
this.Dispose false
Class BaseClass : Implements IDisposable
' Flag: Has Dispose already been called?
Dim disposed As Boolean = False
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Return
If disposing Then
' Free any other managed objects here.
'
End If
' Free any unmanaged objects here.
'
disposed = True
End Sub
Protected Overrides Sub Finalize()
Dispose(disposing:=False)
End Sub
End Class
Subkelas harus menerapkan pola sekali pakai sebagai berikut:
- Mereka harus mengambil alih
Dispose(Boolean)
dan memanggil implementasi kelasDispose(Boolean)
dasar. - Mereka dapat menyediakan finalizer jika diperlukan. Finalizer harus memanggil
Dispose(false)
.
Perhatikan bahwa kelas turunan tidak mengimplementasikan IDisposable antarmuka itu sendiri dan tidak menyertakan metode tanpa Dispose parameter. Mereka hanya mengambil alih metode kelas Dispose(Boolean)
dasar.
Fragmen kode berikut mencerminkan pola pembuangan untuk kelas turunan. Ini mengasumsikan bahwa jenis Anda tidak mengambil Object.Finalize alih metode .
using System;
using System.IO;
using System.Runtime.InteropServices;
class MyDerivedClass : MyBaseClass
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a FileStream instance.
FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
fs.Dispose();
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
open Microsoft.Win32.SafeHandles
open System
type MyDerivedClass() =
inherit MyBaseClass()
// Flag: Has Dispose already been called?
let mutable disposed = false
// Instantiate a FileStream instance.
let fs = new FileStream("test.txt", FileMode.OpenOrCreate)
// Implementation of Dispose pattern.
override _.Dispose(disposing) =
if not disposed then
if disposing then
fs.Dispose()
// Free any other managed objects here.
// Free any unmanaged objects here.
disposed <- true
// Call base class implementation.
base.Dispose disposing
Imports System.IO
Imports System.Runtime.InteropServices
Class DerivedClass2 : Inherits BaseClass2
' Flag: Has Dispose already been called?
Dim disposed As Boolean = False
' Instantiate a FileStream instance.
Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(disposing As Boolean)
If disposed Then Return
If disposing Then
fs.Dispose()
' Free any other managed objects here.
'
End If
' Free any unmanaged objects here.
'
disposed = True
' Call base class implementation.
MyBase.Dispose(disposing)
End Sub
End Class