Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo fornisce osservazioni supplementari alla documentazione di riferimento per questa API.
Scopo principale dell'interfaccia 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 avrà luogo la raccolta dei rifiuti. 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.
Avvertimento
È una modifica critica aggiungere l'interfaccia IDisposable a una classe esistente. Poiché i consumatori preesistenti del tuo tipo non possono chiamare Dispose, non è possibile essere certi che le risorse non gestite trattenute dal tuo 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, dovresti chiamare l'implementazione dell'oggetto IDisposable.Dispose quando hai finito di usarlo. 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
usingin C# e Visual Basic, e l'istruzione ouselausingfunzione in F#. - Eseguendo il wrapping della chiamata all'implementazione IDisposable.Dispose in un
try/finallyblocco.
Annotazioni
Documentazione per i tipi che implementano IDisposable tenere presente tale aspetto e includendo un promemoria per chiamare la 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'istruzionetry/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 consumatori del vostro tipo hanno la possibilità di 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 ulteriori informazioni sull'implementazione di IDisposable.Dispose, 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 per qualunque tipo che non sia sealed (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 finalizzatore.
Il frammento di codice seguente riflette il modello dispose per le classi di base. Si presuppone che il tipo non esegua l'override del metodo Object.Finalize.
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 eliminabile come segue:
- Devono eseguire l'override di
Dispose(Boolean)e chiamare l'implementazione della classe di baseDispose(Boolean). - Se necessario, possono fornire un completatore. 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 esegua l'override del metodo Object.Finalize.
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