Disponi modello
Quando una classe controlla la durata delle risorse non gestite, devi almeno implementare IDisposable
. Ciò consente ai chiamanti di rilasciare in modo deterministico la risorsa non gestita chiamando sia Dispose
che con un'istruzione using
:
using (var unmanaged = GetUnmanagedThing())
{
// Doing stuff with unmanaged
}
L'implementazione di IDisposable
è relativamente semplice. Nel tuo caso ogni istanza dovrebbe essere costruita con un riferimento al gestore e dovrebbe chiamare il manager quando sono eliminati. Assicurati di seguire queste linee guida:
-
Dispose
può essere chiamato più volte per un singolo oggetto, assicurati che il tuo metodo Dispose
lo gestisca.
- Non lancia eccezioni da
Dispose
a meno che l'intero processo non vada a fuoco.
- Assicurati di interrompere l'utilizzo dei metodi sull'oggetto quando è stato eliminato, in genere lanciando
ObjectDisposedException
.
Il articolo sui modelli di smaltimento MSDN entra molto di più dettaglio. Questa pagina ti consiglia di implementare la logica di smaltimento in un metodo virtuale Dispose(bool disposing)
in quanto consente ai finalizzatori e alle classi derivate di gestire correttamente lo smaltimento degli oggetti. Se il tuo oggetto non ha ereditari e non usa la finalizzazione, questo pattern non è necessario e puoi semplicemente implementare direttamente il metodo Dispose
.
La finalizzazione
Garantire che le risorse non gestite vengano distrutte quando un oggetto viene sottoposto a Garbage Collection (senza essere stato eliminato per primo) coinvolge i finalizzatori, che sono notoriamente difficili da implementare correttamente perché tutto ciò che sai è sbagliato . In particolare, gli oggetti possono essere disponibili per la raccolta prima di quanto si pensi, ad esempio un oggetto può diventare idoneo per la raccolta durante l'esecuzione di un metodo su quello stesso oggetto . Occorre quindi prestare attenzione per garantire che le risorse gestite non vengano smaltite mentre sono ancora in uso.
I finalizzatori vengono eseguiti solo dopo che un oggetto è stato sottoposto a garbage collection, che non è deterministico. Potrebbe esserci un lungo ritardo tra il momento in cui un oggetto non viene più referenziato e quando viene finalizzato, il che significa un lungo ritardo prima che le risorse non gestite vengano distrutte. Inoltre i finalizzatori comportano una penalizzazione delle prestazioni poiché il finalizzatore deve essere programmato per essere eseguito e la memoria per l'oggetto non può essere recuperata fino al termine dell'esecuzione del finalizzatore.
Se la tua applicazione è sensibile alle prestazioni, dovresti cercare di smaltire le risorse non gestite utilizzando il modello Dispose, il che rende la finalizzazione inutile. Pertanto il mio consiglio sarebbe di evitare di basarsi sulla finalizzazione e invece di garantire che tutte le parti della propria applicazione utilizzino correttamente il modello di eliminazione . Puoi aggiungere la registrazione al tuo finalizzatore per assicurarti che il pattern di smaltimento non venga seguito correttamente:
public void Dispose() {
// Implement dispose here....
GC.SuppressFinalize(this);
}
~UnmanagedThing() {
Log.Warning("Unmanaged thing not properly disposed");
}
Se questa soluzione non è adatta, potresti essere in grado di utilizzare un SafeHandle per smaltire le risorse non gestite.
No davvero, voglio scrivere un finalizzatore
L'idea generale è di garantire che il tuo oggetto sia irraggiungibile, ad es. facendo in modo che il tuo manager abbia solo un riferimento debole al tuo oggetto, o che il tuo manager abbia un riferimento a un oggetto nidificato. Se il tuo oggetto diventa idoneo per la distruzione, il finalizzatore (si spera) verrà chiamato e potrà essere utilizzato per rilasciare le tue risorse non gestite.