Interfaccia System.IDisposable
Questo articolo fornisce osservazioni supplementari alla documentazione di riferimento per questa API.
L'uso principale dell'interfaccia consiste nel IDisposable rilasciare risorse non gestite. Il Garbage Collector rilascia automaticamente la memoria allocata a un oggetto gestito quando tale oggetto non viene più usato. Tuttavia, non è possibile prevedere quando si verificherà l'operazione di Garbage Collection. Inoltre, Il Garbage Collector non conosce risorse non gestite, ad esempio handle di finestra o file e flussi aperti.
Usare il Dispose metodo di questa interfaccia per rilasciare in modo esplicito le risorse non gestite insieme al Garbage Collector. Il consumer di un oggetto può chiamare questo metodo quando l'oggetto non è più necessario.
Avviso
Si tratta di una modifica che causa un'interruzione per aggiungere l'interfaccia IDisposable a una classe esistente. Poiché i consumer preesistenti del tipo non possono chiamare Dispose, non è possibile essere certi che le risorse non gestite mantenute dal tipo verranno rilasciate.
Poiché l'implementazione IDisposable.Dispose viene chiamata dal consumer di un tipo quando le risorse di proprietà di un'istanza non sono più necessarie, è necessario eseguire il wrapping dell'oggetto gestito in un SafeHandle oggetto (l'alternativa consigliata) oppure eseguire l'override per liberare Object.Finalize risorse non gestite nel caso in cui il consumer dimentica di chiamare Dispose.
Importante
In .NET Framework il compilatore C++ supporta l'eliminazione deterministica delle risorse e non consente l'implementazione diretta del Dispose metodo.
Per informazioni dettagliate sull'uso di questa interfaccia e del Object.Finalize metodo, vedere gli argomenti Garbage Collection e Implementazione di un metodo Dispose.
Usare un oggetto che implementa IDisposable
Se l'app usa semplicemente un oggetto che implementa l'interfaccia IDisposable , devi chiamare l'implementazione dell'oggetto al termine dell'uso IDisposable.Dispose . A seconda del linguaggio di programmazione, è possibile eseguire questa operazione in uno dei due modi seguenti:
- Usando un costrutto di linguaggio, ad esempio l'istruzione
using
in C# e Visual Basic, e l'istruzione ousing
lause
funzione in F#. - Eseguendo il wrapping della chiamata all'implementazione IDisposable.Dispose in un
try
/finally
blocco.
Nota
Documentazione per i tipi che implementano IDisposable si noti che il fatto e includere un promemoria per chiamare la relativa Dispose implementazione.
Istruzione Using C#, F#e Visual Basic
Se il linguaggio supporta un costrutto come l'istruzione using in C#, l'istruzione Using in Visual Basic o l'istruzione use in F#, è possibile usarla invece di chiamare IDisposable.Dispose in modo esplicito se stessi. Nell'esempio seguente viene usato questo approccio per definire una WordCount
classe che mantiene le informazioni su un file e il numero di parole in esso contenute.
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
L'istruzione using
(use
espressione in F#) è in realtà una praticità sintattica. In fase di compilazione, il compilatore del linguaggio implementa il linguaggio intermedio (IL) per un try
/finally
blocco.
Per altre informazioni sull'istruzione using
, vedere gli argomenti Using Statement o using Statement .
Blocco Try/Finally
Se il linguaggio di programmazione non supporta un costrutto come l'istruzione using
in C# o Visual Basic o l'istruzione use
in F#, oppure se si preferisce non usarlo, è possibile chiamare l'implementazione IDisposable.Dispose dal finally
blocco di un'istruzione/try
finally
. Nell'esempio seguente il using
blocco dell'esempio precedente viene sostituito con un try
/finally
blocco .
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
Per altre informazioni sul try
/finally
modello, vedere Prova... Prendere... Infine Istruzione, try-finally, try... finally Expression o try-finally Statement.
Implementare IDisposable
È consigliabile implementare IDisposable se il tipo usa direttamente le risorse non gestite o se si desidera usare manualmente le risorse eliminabili. I consumer del tipo possono chiamare l'implementazione IDisposable.Dispose per liberare risorse quando l'istanza non è più necessaria. Per gestire i casi in cui non riescono a chiamare Dispose, è necessario usare una classe derivata da SafeHandle per eseguire il wrapping delle risorse non gestite oppure eseguire l'override del Object.Finalize metodo per un tipo di riferimento. In entrambi i casi, si usa il Dispose metodo per eseguire qualsiasi pulizia necessaria dopo aver usato le risorse non gestite, ad esempio liberando, rilasciando o reimpostando le risorse non gestite. Per altre informazioni sull'implementazione IDisposable.Disposedi , vedere l'overload del metodo Dispose(bool).
Importante
Se si definisce una classe di base che usa risorse non gestite e che ha, o probabilmente, sottoclassi che devono essere eliminate, è necessario implementare il IDisposable.Dispose metodo e fornire un secondo overload di Dispose
, come illustrato nella sezione successiva.
IDisposable e la gerarchia di ereditarietà
Una classe base con sottoclassi che devono essere eliminabili deve essere implementata IDisposable come indicato di seguito. È consigliabile usare questo modello ogni volta che si implementa IDisposable su qualsiasi tipo che non sealed
sia (NotInheritable
in Visual Basic).
- Deve fornire un metodo pubblico, non virtuale Dispose() e un metodo virtuale
Dispose(Boolean disposing)
protetto. - Il Dispose() metodo deve chiamare
Dispose(true)
e eliminare la finalizzazione per le prestazioni. - Il tipo di base non deve includere alcun finalizzatori.
Il frammento di codice seguente riflette il modello dispose per le classi di base. Si presuppone che il tipo non esegue l'override del Object.Finalize metodo .
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
Se si esegue l'override del Object.Finalize metodo , la classe deve implementare il modello seguente.
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
Le sottoclassi devono implementare il modello Disposable nel modo seguente:
- Devono eseguire l'override di
Dispose(Boolean)
e chiamare l'implementazioneDispose(Boolean)
della classe di base. - Se necessario, possono fornire un finalizzatore. Il finalizzatore deve chiamare
Dispose(false)
.
Si noti che le classi derivate non implementano l'interfaccia IDisposable e non includono un metodo senza Dispose parametri. Eseguono solo l'override del metodo della classe Dispose(Boolean)
base.
Il frammento di codice seguente riflette il modello dispose per le classi derivate. Si presuppone che il tipo non esegue l'override del Object.Finalize metodo .
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