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.
Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.
Podstawowym zastosowaniem interfejsu IDisposable jest zwalnianie niezarządzanych zasobów. Mechanizm odśmiecania pamięci automatycznie zwalnia pamięć przydzieloną do obiektu zarządzanego, gdy ten obiekt nie jest już używany. Nie można jednak przewidzieć, kiedy nastąpi odzyskiwanie pamięci. Ponadto moduł odśmiecania pamięci nie ma wiedzy na temat niezarządzanych zasobów, takich jak uchwyty okien, ani też otwartych plików i strumieni.
Dispose Użyj metody tego interfejsu, aby jawnie zwolnić niezarządzane zasoby w połączeniu z modułem odśmiecanie pamięci. Użytkownik obiektu może wywołać tę metodę, gdy obiekt nie jest już potrzebny.
Ostrzeżenie
Dodanie interfejsu IDisposable do istniejącej klasy jest zmianą powodującą niezgodność. Ponieważ wstępnie istniejący użytkownicy typu nie mogą wywołać Dispose, nie można mieć pewności, że niezarządzane zasoby przechowywane przez typ zostaną zwolnione.
Ponieważ implementacja IDisposable.Dispose jest wywoływana przez użytkownika typu, gdy zasoby należące do wystąpienia nie są już potrzebne, należy opakować obiekt zarządzany w zalecaną alternatywę SafeHandle lub przesłonić Object.Finalize w celu zwolnienia niezarządzanych zasobów w przypadku, gdy użytkownik zapomni wywołać metodę Dispose.
Ważne
W programie .NET Framework kompilator języka C++ obsługuje deterministyczne usuwanie zasobów i nie zezwala na bezpośrednią implementację metody.
Aby zapoznać się ze szczegółowym omówieniem sposobu użycia tego interfejsu Object.Finalize i metody, zobacz temat Odzyskiwanie pamięci i Implementowanie metody usuwania .
Użyj obiektu implementującego interfejs IDisposable
Jeśli aplikacja używa po prostu obiektu, który implementuje IDisposable interfejs, należy wywołać implementację obiektu IDisposable.Dispose po zakończeniu korzystania z niego. W zależności od języka programowania można to zrobić na jeden z dwóch sposobów:
- Korzystając z konstrukcji językowych, takich jak na przykład instrukcja
using
w języku C# i Visual Basic, oraz instrukcjause
lub funkcjausing
w języku F#. - Zawijając wywołanie implementacji IDisposable.Dispose w blok
try
/finally
.
Uwaga
Dokumentacja typów, które implementują IDisposable, zawiera informację o konieczności wywołania implementacji Dispose oraz przypomnienie o tym fakcie.
Dyrektywa Using w C#, F# i Visual Basic
Jeśli język obsługuje konstrukcję, taką jak instrukcja using w języku C#, instrukcja Using w Visual Basic lub instrukcja use w języku F#, możesz użyć jej zamiast jawnie wywoływać IDisposable.Dispose siebie. W poniższym przykładzie użyto tego podejścia w zdefiniowaniu WordCount
klasy, która zachowuje informacje o pliku i liczbie wyrazów w nim.
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
Instrukcja using
(wyrażenie use
w języku F#) jest w rzeczywistości elementem ułatwiającym składnię. W czasie kompilacji kompilator języka implementuje język pośredni (IL) dla try
/finally
bloku.
Aby uzyskać więcej informacji na temat instrukcji using
, zobacz tematy Using Statement lub using Statement.
Blok Try/Finally
Jeśli język programowania nie obsługuje konstrukcji takiej jak using
instrukcja w języku C# lub Visual Basic albo use
instrukcja w języku F#, lub jeśli nie chcesz jej używać, możesz wywołać IDisposable.Dispose implementację z finally
bloku try
/finally
instrukcji. Poniższy przykład zastępuje blok using
w poprzednim przykładzie blokiem try
/finally
.
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
Aby uzyskać więcej informacji na temat try
/finally
wzorca, zobacz Try...Catch...Finally instrukcja, try-finally, try...finally wyrażenie lub try-finally instrukcja.
Implementowanie funkcji IDisposable
Należy zaimplementować IDisposable , jeśli typ używa zasobów niezarządzanych bezpośrednio lub jeśli chcesz samodzielnie korzystać z zasobów jednorazowych. Użytkownicy twojego typu mogą wywołać implementację IDisposable.Dispose w celu zwolnienia zasobów, gdy instancja nie jest już potrzebna. Aby obsłużyć przypadki, w których nie można wywołać Dispose, należy użyć klasy pochodnej SafeHandle do opakowania niezarządzanych zasobów lub przesłonić metodę Object.Finalize dla typu odwołania. W obu przypadkach użyjesz metody Dispose, aby wykonać wszelkie konieczne sprzątanie po użyciu niezarządzanych zasobów, takich jak zwalnianie, uwalnianie lub resetowanie niezarządzanych zasobów. Aby uzyskać więcej informacji na temat implementowania metody IDisposable.Dispose, zobacz przeciążenie metody Dispose(bool).
Ważne
Jeśli definiujesz klasę bazową, która używa niezarządzanych zasobów i która ma lub prawdopodobnie będzie mieć podklasy, które powinny być usuwane, należy zaimplementować metodę IDisposable.Dispose i podać drugie przeciążenie Dispose
, jak opisano w następnej sekcji.
IDisposable i hierarchia dziedziczenia
Klasa bazowa z podklasami, które powinny być usuwalne, musi implementować IDisposable w następujący sposób. Należy używać tego wzorca zawsze, gdy implementujesz IDisposable na dowolnym typie, który nie jest sealed
(NotInheritable
w Visual Basic).
- Powinna ona udostępnić jedną publiczną, niewirtuacyjną Dispose() metodę i chronioną metodę wirtualną
Dispose(Boolean disposing)
. - Metoda Dispose() musi wywołać
Dispose(true)
i powinna pominąć finalizację dla poprawy wydajności. - Typ podstawowy nie powinien zawierać żadnych finalizatorów.
Poniższy fragment kodu odzwierciedla wzorzec usuwania dla klas bazowych. Przyjęto założenie, że typ nie zastępuje Object.Finalize metody .
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
Jeśli zastąpisz metodę Object.Finalize , klasa powinna zaimplementować następujący wzorzec.
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
Podklasy powinny implementować wzorzec jednorazowego w następujący sposób:
- Muszą one zastąpić
Dispose(Boolean)
i wywołać implementację klasyDispose(Boolean)
bazowej. - W razie potrzeby mogą dostarczyć finalizator. Finalizator musi wywołać
Dispose(false)
.
Należy pamiętać, że klasy pochodne nie implementują interfejsu IDisposable i nie zawierają metody bez Dispose parametrów. Zastępują tylko metodę klasy Dispose(Boolean)
bazowej.
Poniższy fragment kodu odzwierciedla wzorzec usuwania dla klas pochodnych. Przyjęto założenie, że typ nie zastępuje Object.Finalize metody .
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