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.
Il Garbage Collector (GC) di Common Language Runtime recupera la memoria usata dagli oggetti gestiti. In genere, i tipi che usano risorse non gestite implementano l'interfaccia IDisposable o IAsyncDisposable per consentire il recupero delle risorse non gestite. Al termine dell'uso di un oggetto che implementa IDisposable, si chiama l'implementazione del metodo Dispose o DisposeAsync dell'oggetto per eseguire in modo esplicito la pulizia. È possibile eseguire questa operazione in uno dei due modi seguenti:
- Con l'istruzione/dichiarazione
using
di C# (Using
in Visual Basic). - Implementando un
try/finally
blocco e chiamando il metodo Dispose o il metodo DisposeAsync infinally
.
Importante
Il GC non elimina gli oggetti, perché non ha alcuna conoscenza di IDisposable.Dispose() o IAsyncDisposable.DisposeAsync(). Il GC sa solo se un oggetto è finalizzabile (ovvero definisce un Object.Finalize() metodo) e quando è necessario chiamare il finalizzatore dell'oggetto. Per altre informazioni, vedere Funzionamento della finalizzazione. Per altri dettagli sull'implementazione di Dispose
e DisposeAsync
, vedere:
Gli oggetti che implementano System.IDisposable o System.IAsyncDisposable devono essere sempre eliminati correttamente, indipendentemente dall'ambito delle variabili, a meno che non diversamente specificato in modo esplicito. I tipi che definiscono un finalizzatore per rilasciare risorse non gestite di solito chiamano GC.SuppressFinalize dalla loro implementazione Dispose
o DisposeAsync
. La chiamata SuppressFinalize indica al GC che il finalizzatore è già stato eseguito e che l'oggetto non deve essere alzato di livello per la finalizzazione.
Istruzione using
L'istruzioneusing
in C# e l'istruzioneUsing
in Visual Basic semplificano il codice che è necessario scrivere per pulire un oggetto. L'istruzione using
ottiene una o più risorse, esegue le istruzioni specificate e elimina automaticamente l'oggetto. Tuttavia, l'istruzione using
è utile solo per gli oggetti utilizzati nell'ambito del metodo in cui vengono costruiti.
Nell'esempio seguente viene utilizzata l'istruzione using
per creare e rilasciare un System.IO.StreamReader oggetto .
using System.IO;
class UsingStatement
{
static void Main()
{
var buffer = new char[50];
using (StreamReader streamReader = new("file1.txt"))
{
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
}
}
Imports System.IO
Module UsingStatement
Public Sub Main()
Dim buffer(49) As Char
Using streamReader As New StreamReader("File1.txt")
Dim charsRead As Integer
Do While streamReader.Peek() <> -1
charsRead = streamReader.Read(buffer, 0, buffer.Length)
'
' Process characters read.
'
Loop
End Using
End Sub
End Module
Una using
dichiarazione è una sintassi alternativa disponibile in cui vengono rimosse le parentesi graffe e l'ambito è implicito.
using System.IO;
class UsingDeclaration
{
static void Main()
{
var buffer = new char[50];
using StreamReader streamReader = new("file1.txt");
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
}
Anche se la StreamReader classe implementa l'interfaccia IDisposable , che indica che usa una risorsa non gestita, l'esempio non chiama in modo esplicito il StreamReader.Dispose metodo . Quando il compilatore C# o Visual Basic rileva l'istruzione using
, genera un linguaggio intermedio (IL) equivalente al codice seguente che contiene in modo esplicito un try/finally
blocco.
using System.IO;
class TryFinallyGenerated
{
static void Main()
{
var buffer = new char[50];
StreamReader? streamReader = null;
try
{
streamReader = new StreamReader("file1.txt");
int charsRead = 0;
while (streamReader.Peek() != -1)
{
charsRead = streamReader.Read(buffer, 0, buffer.Length);
//
// Process characters read.
//
}
}
finally
{
// If non-null, call the object's Dispose method.
streamReader?.Dispose();
}
}
}
Imports System.IO
Module TryFinallyGenerated
Public Sub Main()
Dim buffer(49) As Char
Dim streamReader As New StreamReader("File1.txt")
Try
Dim charsRead As Integer
Do While streamReader.Peek() <> -1
charsRead = streamReader.Read(buffer, 0, buffer.Length)
'
' Process characters read.
'
Loop
Finally
If streamReader IsNot Nothing Then DirectCast(streamReader, IDisposable).Dispose()
End Try
End Sub
End Module
L'istruzione C# using
consente anche di acquisire più risorse in un'unica istruzione, che è internamente equivalente alle istruzioni annidate using
. Nell'esempio seguente vengono creati due oggetti StreamReader per leggere il contenuto di due file diversi.
using System.IO;
class SingleStatementMultiple
{
static void Main()
{
var buffer1 = new char[50];
var buffer2 = new char[50];
using StreamReader version1 = new("file1.txt"),
version2 = new("file2.txt");
int charsRead1, charsRead2 = 0;
while (version1.Peek() != -1 && version2.Peek() != -1)
{
charsRead1 = version1.Read(buffer1, 0, buffer1.Length);
charsRead2 = version2.Read(buffer2, 0, buffer2.Length);
//
// Process characters read.
//
}
}
}
Blocco try/finally
Anziché racchiudere un blocco try/finally
in un'istruzione using
, puoi scegliere di implementare il blocco try/finally
direttamente. Può trattarsi dello stile di scrittura del codice personale oppure potrebbe essere necessario eseguire questa operazione per uno dei motivi seguenti:
- Per includere un blocco
catch
che gestisce le eccezioni sollevate nel bloccotry
. In caso contrario, tutte le eccezioni generate all'interno dell'istruzioneusing
non vengono gestite. - Per creare un'istanza di un oggetto che implementa IDisposable il cui ambito non è locale nel blocco in cui è dichiarato.
L'esempio seguente è simile all'esempio precedente, ad eccezione del fatto che usa un blocco try/catch/finally
per creare un'istanza, usare ed eliminare un oggetto StreamReader e per gestire eventuali eccezioni generate dal costruttore StreamReader e il suo metodo ReadToEnd. Il codice nel blocco finally
verifica che l'oggetto che implementa IDisposable non sia null
prima di chiamare il metodo Dispose. In caso contrario, può verificarsi un'eccezione NullReferenceException in fase di esecuzione.
using System;
using System.Globalization;
using System.IO;
class TryExplicitCatchFinally
{
static void Main()
{
StreamReader? streamReader = null;
try
{
streamReader = new StreamReader("file1.txt");
string contents = streamReader.ReadToEnd();
var info = new StringInfo(contents);
Console.WriteLine($"The file has {info.LengthInTextElements} text elements.");
}
catch (FileNotFoundException)
{
Console.WriteLine("The file cannot be found.");
}
catch (IOException)
{
Console.WriteLine("An I/O error has occurred.");
}
catch (OutOfMemoryException)
{
Console.WriteLine("There is insufficient memory to read the file.");
}
finally
{
streamReader?.Dispose();
}
}
}
Imports System.Globalization
Imports System.IO
Module TryExplicitCatchFinally
Sub Main()
Dim streamReader As StreamReader = Nothing
Try
streamReader = New StreamReader("file1.txt")
Dim contents As String = streamReader.ReadToEnd()
Dim info As StringInfo = New StringInfo(contents)
Console.WriteLine($"The file has {info.LengthInTextElements} text elements.")
Catch e As FileNotFoundException
Console.WriteLine("The file cannot be found.")
Catch e As IOException
Console.WriteLine("An I/O error has occurred.")
Catch e As OutOfMemoryException
Console.WriteLine("There is insufficient memory to read the file.")
Finally
If streamReader IsNot Nothing Then streamReader.Dispose()
End Try
End Sub
End Module
È possibile seguire questo modello di base se si sceglie di implementare o si è obbligati a implementare un blocco try/finally
, perché il linguaggio di programmazione non supporta un'istruzione using
, ma consente chiamate dirette al metodo Dispose.
Membri dell'istanza IDisposable
Se una classe è proprietaria di un campo di istanza o di una proprietà e il relativo tipo implementa IDisposable, la classe deve implementare IDisposableanche . Per ulteriori informazioni, vedere Implementare un'eliminazione a cascata.