Distruttori (Guida per programmatori C#)
I distruttori sono utilizzati per distruggere istanze di classi.
Note
I distruttori non possono essere definiti nelle strutture, ma solamente nelle classi.
Per una classe è possibile utilizzare un solo distruttore.
I distruttori non possono essere ereditati e non è possibile eseguirne l'overload.
I distruttori non possono essere chiamati. Vengono richiamati automaticamente.
Un distruttore non accetta modificatori né parametri.
Di seguito è riportato un esempio di dichiarazione di un distruttore per la classe Car:
class Car
{
~Car() // destructor
{
// cleanup statements...
}
}
Il distruttore chiama in modo implicito il metodo Finalize sulla classe di base dell'oggetto. Il codice del distruttore riportato sopra viene quindi convertito implicitamente nel codice seguente:
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
In questo modo, il metodo Finalize viene chiamato in modo ricorsivo per tutte le istanze nella catena di ereditarietà, dalla più derivata alla meno derivata.
Nota
Non utilizzare distruttori vuoti. Quando una classe contiene un distruttore, viene creata una voce nella coda Finalize. Quando si chiama il distruttore, viene richiamato Garbage Collector per elaborare la coda. Se il distruttore è vuoto, si verifica semplicemente un calo di prestazioni.
Il programmatore non ha alcun controllo sul momento in cui il distruttore viene chiamato, poiché questa decisione dipende dal Garbage Collector. Il Garbage Collector controlla gli oggetti che non vengono più utilizzati dall'applicazione e, se considera un oggetto idoneo per la distruzione, chiama il distruttore (se presente) e recupera la memoria utilizzata per archiviare l'oggetto in questione. I distruttori vengono chiamati anche quando si esce dal programma.
È possibile imporre l'esecuzione della Garbage Collection chiamando Collect. Nella maggior parte dei casi, tuttavia, è preferibile non effettuare questa operazione per evitare potenziali problemi di prestazioni.
Utilizzo dei distruttori per liberare risorse
In generale in C# non sono necessarie le numerose attività di gestione della memoria richieste quando si sviluppa con un linguaggio che non ha come destinazione un runtime con Garbage Collection. Il Garbage Collector di .NET Framework, infatti, gestisce in modo implicito l'allocazione e il rilascio di memoria per gli oggetti. Tuttavia, quando l'applicazione incapsula risorse non gestite come finestre, file e connessioni di rete, è necessario utilizzare i distruttori per rendere disponibili tali risorse. Quando l'oggetto può essere distrutto, il Garbage Collector esegue il metodo Finalize dell'oggetto.
Rilascio esplicito di risorse
Se l'applicazione utilizza una risorsa esterna che consuma molta memoria, si consiglia di fornire un modo per rilasciare la risorsa in modo esplicito prima che il Garbage Collector renda disponibile l'oggetto. A questo scopo, è possibile implementare un metodo Dispose dall'interfaccia IDisposable che esegua la pulitura necessaria per l'oggetto. Questo consente di migliorare notevolmente le prestazioni dell'applicazione. Nonostante questa possibilità di controllo esplicito sulle risorse, il distruttore è un metodo efficace per salvaguardare la pulitura delle risorse nei casi in cui la chiamata al metodo Dispose non venga eseguita correttamente.
Per ulteriori informazioni sulla pulitura delle risorse, vedere i seguenti argomenti:
Esempio
Nell'esempio riportato di seguito vengono create tre classi che costituiscono una catena di ereditarietà. La classe First è la classe base, Second è derivata da First e Third è derivata da Second. Per tutte e tre le classi sono definiti dei distruttori. In Main() viene creata un'istanza della classe più derivata. Quando il programma viene eseguito, i distruttori delle tre classi vengono chiamati automaticamente e in ordine, dalla classe più derivata alla meno derivata.
class First
{
~First()
{
System.Diagnostics.Trace.WriteLine("First's destructor is called.");
}
}
class Second : First
{
~Second()
{
System.Diagnostics.Trace.WriteLine("Second's destructor is called.");
}
}
class Third : Second
{
~Third()
{
System.Diagnostics.Trace.WriteLine("Third's destructor is called.");
}
}
class TestDestructors
{
static void Main()
{
Third t = new Third();
}
}
/* Output (to VS Output Window):
Third's destructor is called.
Second's destructor is called.
First's destructor is called.
*/
Specifiche del linguaggio C#
Per ulteriori informazioni, vedere la Specifiche del linguaggio C#. La specifica del linguaggio è la fonte ufficiale per la sintassi e l'utilizzo di C#.
Vedere anche
Riferimenti
Costruttori (Guida per programmatori C#)