Smaltire oggetti

Nell'articolo, Coding New Instances of Objects, ho scritto sui vari modi in cui Novitá possono essere create istanze di oggetti. Il problema opposto, disporre un oggetto, è qualcosa di cui non dovrai preoccuparti in VB.NET molto spesso. .NET include una tecnologia chiamata Netturbino (GC) che di solito si occupa di tutto dietro le quinte in modo silenzioso ed efficiente. Ma occasionalmente, di solito quando si utilizzano flussi di file, oggetti sql o oggetti grafici (GDI +) (ovvero, risorse non gestite), potrebbe essere necessario assumere il controllo dell'eliminazione degli oggetti nel proprio codice.

Innanzitutto, alcuni retroscena

Proprio come un costruttore (il Novitá parola chiave) crea un nuovo oggetto, un distruttore è un metodo che viene chiamato quando un oggetto viene distrutto. Ma c'è un problema. Le persone che hanno creato .NET si sono rese conto che era una formula per i bug se due diversi pezzi di codice potevano effettivamente distruggere un oggetto. Quindi .NET GC ha effettivamente il controllo e di solito è l'unico codice che può distruggere l'istanza dell'oggetto. Il GC distrugge un oggetto quando lo decide e non prima. Normalmente, dopo che un oggetto esce dall'ambito, viene rilasciato da Common Language Runtime (CLR). Il GC distrugge gli oggetti quando CLR necessita di più memoria libera. Quindi la linea di fondo è che non puoi prevedere quando GC distruggerà effettivamente l'oggetto.

(Welllll ... Questo è vero quasi sempre. Puoi chiamare GC.Collect e forzare un ciclo di raccolta dei rifiuti, ma le autorità universalmente dicono che è una cattiva idea e totalmente inutile.)

Ad esempio, se il tuo codice ha creato un file Cliente oggetto, può sembrare che questo codice lo distruggerà di nuovo.

Cliente = Niente

Ma non è così. (L'impostazione di un oggetto su Nothing viene comunemente chiamata, dereferenziazione l'oggetto.) In realtà, significa solo che la variabile non è più associata a un oggetto. In un momento successivo, il GC noterà che l'oggetto è disponibile per la distruzione.

A proposito, per gli oggetti gestiti, niente di tutto questo è realmente necessario. Sebbene un oggetto come un Button offrirà un metodo Dispose, non è necessario utilizzarlo e poche persone lo fanno. I componenti Windows Form, ad esempio, vengono aggiunti a un oggetto contenitore denominato componenti. Quando chiudi un modulo, il suo metodo Dispose viene chiamato automaticamente. Di solito, devi solo preoccuparti di tutto ciò quando usi oggetti non gestiti, e anche in questo caso solo per ottimizzare il tuo programma.

Il modo consigliato per rilasciare tutte le risorse che potrebbero essere trattenute da un oggetto è chiamare il file lineamenti metodo per l'oggetto (se disponibile) e quindi dereferenziare l'oggetto.

 Customer.Dispose () Customer = Nothing 

Poiché GC distruggerà un oggetto orfano, indipendentemente dal fatto che imposti la variabile oggetto su Nothing, non è realmente necessario.

Un altro modo consigliato per assicurarsi che gli oggetti vengano distrutti quando non sono più necessari è inserire il codice che utilizza un oggetto in un file utilizzando bloccare. Un blocco Using garantisce lo smaltimento di una o più di tali risorse quando il codice ha terminato con esse.

Nella serie GDI +, il utilizzando block viene utilizzato abbastanza frequentemente per gestire questi fastidiosi oggetti grafici. Per esempio ...

 Utilizzo di myBrush As LinearGradientBrush _ = New LinearGradientBrush (_ Me.ClientRectangle, _ Color.Blue, Color.Red, _ LinearGradientMode.Horizontal) <... altro codice ...> Fine utilizzo 

myBrush viene eliminato automaticamente quando viene eseguita la fine del blocco.

L'approccio GC alla gestione della memoria è un grande cambiamento rispetto al modo in cui lo faceva VB6. Gli oggetti COM (utilizzati da VB6) venivano distrutti quando un contatore interno di riferimenti raggiungeva lo zero. Ma era troppo facile commettere un errore, quindi il contatore interno era spento. (Poiché la memoria era impegnata e non disponibile per altri oggetti quando ciò è accaduto, ciò è stato chiamato "perdita di memoria".) Invece, GC controlla effettivamente se qualcosa fa riferimento a un oggetto e lo distrugge quando non ci sono più riferimenti. L'approccio GC ha una buona storia in linguaggi come Java ed è uno dei grandi miglioramenti in .NET.

Nella pagina successiva, esamineremo l'interfaccia IDisposable ... l'interfaccia da utilizzare quando è necessario disporre di oggetti non gestiti nel proprio codice.

Se codifichi un tuo oggetto che utilizza risorse non gestite, dovresti usare il IDisposable interfaccia per l'oggetto. Microsoft semplifica questo compito includendo uno snippet di codice che crea il modello giusto per te.

--------
Fare clic qui per visualizzare l'illustrazione
Fare clic sul pulsante Indietro nel browser per tornare indietro
--------

Il codice aggiunto ha questo aspetto (VB.NET 2008):

 Classe ResourceClass Implementa IDisposable 'Per rilevare chiamate ridondanti Privato disposto As Boolean = False' IDisposable Protected Overridable Sub Dispose (_ ByVal disposing As Boolean) If Not Me.disposed Then If disposing Then 'Free other state (managed objects). End If 'Libera il tuo stato (oggetti non gestiti). 'Imposta i campi grandi su null. End If Me.disposed = True End Sub #Region "IDisposable Support" 'Questo codice aggiunto da Visual Basic per' implementare correttamente il pattern usa e getta. Public Sub Dispose () Implements IDisposable.Dispose 'Non modificare questo codice. "Metti il ​​codice di pulizia in" Dispose (ByVal disposing As Boolean) sopra. Dispose (True) GC.SuppressFinalize (Me) End Sub Protected Overrides Sub Finalize () 'Non modificare questo codice. "Metti il ​​codice di pulizia in" Dispose (ByVal disposing As Boolean) sopra. Dispose (False) MyBase.Finalize () End Sub #End Region End Class 

lineamenti è quasi un modello di progettazione dello sviluppatore "forzato" in .NET. C'è davvero solo un modo corretto per farlo e questo è tutto. Potresti pensare che questo codice faccia qualcosa di magico. Non è così.

Prima nota che la bandiera interna disposto semplicemente cortocircuita l'intera cosa in modo da poter chiamare Smaltire (smaltire) tutte le volte che vuoi.

Il codice ...

 GC.SuppressFinalize (Me) 

... rende il tuo codice più efficiente dicendo al GC che l'oggetto è già stato eliminato (un'operazione "costosa" in termini di cicli di esecuzione). Finalize è protetto perché GC lo chiama automaticamente quando un oggetto viene distrutto. Non dovresti mai chiamare Finalize. Il booleano smaltimento indica al codice se il codice ha avviato l'eliminazione dell'oggetto (True) o se l'ha fatto il GC (come parte del file ultimare sub. Notare che l'unico codice che utilizza Boolean smaltimento è:

 Se si elimina Allora 'Libera altro stato (oggetti gestiti). Finisci se 

Quando smaltisci un oggetto, tutte le sue risorse devono essere smaltite. Quando il Garbage Collector di CLR elimina un oggetto, è necessario eliminare solo le risorse non gestite perché il Garbage Collector si occupa automaticamente delle risorse gestite.

L'idea alla base di questo frammento di codice è l'aggiunta di codice per occuparsi degli oggetti gestiti e non gestiti nelle posizioni indicate.

Quando si deriva una classe da una classe base che implementa IDisposable, non è necessario eseguire l'override di nessuno dei metodi di base a meno che non si utilizzino altre risorse che devono essere eliminate. In tal caso, la classe derivata deve sovrascrivere il metodo Dispose (smaltimento) della classe base per eliminare le risorse della classe derivata. Ma ricorda di chiamare il metodo Dispose (disposing) della classe base.

 Sostituzioni protette Sub Dispose (ByVal disposing As Boolean) If Not Me.disposed Then If disposing Then 'Add your code to free managed resources. End If 'Aggiungi il tuo codice per liberare risorse non gestite. End If MyBase.Dispose (disposing) End Sub 

L'argomento può essere leggermente opprimente. Lo scopo della spiegazione qui è di "demistificare" ciò che sta realmente accadendo perché la maggior parte delle informazioni che puoi trovare non te lo dice!