System.IDisposable interface
In dit artikel vindt u aanvullende opmerkingen in de referentiedocumentatie voor deze API.
Het primaire gebruik van de IDisposable interface is het vrijgeven van onbeheerde resources. De garbagecollector geeft automatisch het geheugen vrij dat is toegewezen aan een beheerd object wanneer dat object niet meer wordt gebruikt. Het is echter niet mogelijk om te voorspellen wanneer garbagecollection plaatsvindt. Bovendien heeft de garbagecollector geen kennis van onbeheerde resources, zoals venstergrepen, of open bestanden en stromen.
Gebruik de Dispose methode van deze interface om niet-beheerde resources expliciet vrij te geven in combinatie met de garbagecollector. De consument van een object kan deze methode aanroepen wanneer het object niet meer nodig is.
Waarschuwing
Het is een belangrijke wijziging om de IDisposable interface toe te voegen aan een bestaande klasse. Omdat bestaande consumenten van uw type niet kunnen worden aangeroepen Dispose, kunt u er niet zeker van zijn dat onbeheerde resources die door uw type worden bewaard, worden vrijgegeven.
Omdat de IDisposable.Dispose implementatie wordt aangeroepen door de consument van een type wanneer de resources die eigendom zijn van een exemplaar niet meer nodig zijn, moet u het beheerde object verpakken in een SafeHandle (het aanbevolen alternatief), of moet u overschrijven Object.Finalize naar gratis onbeheerde resources in het geval dat de consument vergeet aan te roepen Dispose.
Belangrijk
In .NET Framework ondersteunt de C++-compiler deterministische verwijdering van resources en staat de directe implementatie van de Dispose methode niet toe.
Zie de onderwerpen Garbagecollection en Het implementeren van een verwijderingsmethode voor een gedetailleerde bespreking van de manier waarop deze interface en de Object.Finalize methode worden gebruikt.
Een object gebruiken dat IDisposable implementeert
Als uw app gewoon gebruikmaakt van een object dat de IDisposable interface implementeert, moet u de implementatie van IDisposable.Dispose het object aanroepen wanneer u klaar bent met het gebruik ervan. Afhankelijk van uw programmeertaal kunt u dit op twee manieren doen:
- Door gebruik te maken van een taalconstructie zoals de
using
instructie in C# en Visual Basic en deuse
instructie ofusing
functie in F#. - Door de aanroep naar de IDisposable.Dispose implementatie in een
try
/finally
blok te verpakken.
Notitie
Documentatie voor typen die implementeren IDisposable , houd er rekening mee dat feit en een herinnering bevatten om de Dispose implementatie aan te roepen.
De instructie C#, F# en Visual Basic Using
Als uw taal ondersteuning biedt voor een constructie zoals de using-instructie in C#, de using-instructie in Visual Basic of de use-instructie in F#, kunt u deze gebruiken in plaats van uzelf expliciet aan te roepen IDisposable.Dispose . In het volgende voorbeeld wordt deze methode gebruikt bij het definiëren van een WordCount
klasse die informatie over een bestand en het aantal woorden erin bewaart.
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
De using
instructie (use
expressie in F#) is eigenlijk een syntactisch gemak. Tijdens het compileren implementeert de taalcompilator de tussenliggende taal (IL) voor een try
/finally
blok.
Zie de onderwerpen Using Statement of Using Statement (Instructie gebruiken) voor meer informatie over de using
instructie.
Het blok Try/Finally
Als uw programmeertaal geen ondersteuning biedt voor een constructie zoals de using
instructie in C# of Visual Basic, of de use
instructie in F#, of als u deze liever niet gebruikt, kunt u de IDisposable.Dispose implementatie aanroepen vanuit het finally
blok van een try
/finally
instructie. In het volgende voorbeeld wordt het using
blok in het vorige voorbeeld vervangen door een 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
Zie Try voor meer informatie over hetfinally
try
/patroon... Vangen... Ten slotte instructie, try-finally, try... ten slotte expressie, of try-finally Statement.
IDisposable implementeren
U moet implementeren IDisposable als uw type rechtstreeks onbeheerde resources gebruikt of als u zelf wegwerpbronnen wilt gebruiken. De consumenten van uw type kunnen uw IDisposable.Dispose implementatie aanroepen naar gratis resources wanneer het exemplaar niet meer nodig is. Als u aanvragen wilt afhandelen waarin ze niet kunnen worden aangeroepen Dispose, moet u een klasse gebruiken die is afgeleid van het verpakken van SafeHandle de niet-beheerde resources, of moet u de Object.Finalize methode voor een verwijzingstype overschrijven. In beide gevallen gebruikt u de Dispose methode om de benodigde opschoning uit te voeren nadat u de niet-beheerde resources hebt gebruikt, zoals het vrijmaken, vrijgeven of opnieuw instellen van de onbeheerde resources. Zie de overbelasting van de methode Dispose(bool) voor meer informatie over het implementeren.IDisposable.Dispose
Belangrijk
Als u een basisklasse definieert die gebruikmaakt van niet-beheerde resources en die wel of waarschijnlijk subklassen hebben die moeten worden verwijderd, moet u de IDisposable.Dispose methode implementeren en een tweede overbelasting van Dispose
, zoals besproken in de volgende sectie.
IDisposable en de overnamehiërarchie
Een basisklasse met subklassen die wegwerpbaar moeten zijn, moet als volgt worden geïmplementeerd IDisposable . U moet dit patroon gebruiken wanneer u implementeert IDisposable voor elk type dat niet sealed
(NotInheritable
in Visual Basic) is.
- Het moet één openbare, niet-virtuele Dispose() methode en een beveiligde virtuele
Dispose(Boolean disposing)
methode bieden. - De Dispose() methode moet worden aangeroepen
Dispose(true)
en moet de voltooien voor prestaties onderdrukken. - Het basistype mag geen finalizers bevatten.
Het volgende codefragment weerspiegelt het verwijderingspatroon voor basisklassen. Hierbij wordt ervan uitgegaan dat uw type de Object.Finalize methode niet overschrijft.
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
Als u de Object.Finalize methode overschrijft, moet uw klasse het volgende patroon implementeren.
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
Subklassen moeten het wegwerppatroon als volgt implementeren:
- Ze moeten de basisklasse-implementatie
Dispose(Boolean)
overschrijvenDispose(Boolean)
en aanroepen. - Ze kunnen indien nodig een finalizer bieden. De finalizer moet aanroepen
Dispose(false)
.
Houd er rekening mee dat afgeleide klassen zelf de IDisposable interface niet implementeren en geen parameterloze Dispose methode bevatten. Ze overschrijven alleen de basisklassemethode Dispose(Boolean)
.
Het volgende codefragment weerspiegelt het verwijderingspatroon voor afgeleide klassen. Hierbij wordt ervan uitgegaan dat uw type de Object.Finalize methode niet overschrijft.
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