Come disporre una class in .net?

Il garbage collector .NET alla fine libererà la memoria, ma cosa succederebbe se volessi riavere quella memoria immediatamente? Quale codice è necessario utilizzare in una class MyClass per chiamare

 MyClass.Dispose() 

e liberare tutto lo spazio utilizzato da variabili e oggetti in MyClass ?

IDisposable non ha nulla a che fare con la liberazione della memoria. IDisposable è uno schema per liberare risorse non gestite – e la memoria è decisamente una risorsa gestita.

I collegamenti che puntano a GC.Collect () sono la risposta corretta, sebbene l’uso di questa funzione sia generalmente scoraggiato dalla documentazione di Microsoft .NET.

Edit: Avendo guadagnato una notevole quantità di karma per questa risposta, sento una certa responsabilità nel elaborarlo, per evitare che un nuovo arrivato alla gestione delle risorse .NET abbia l’impressione sbagliata.

All’interno di un processo .NET, esistono due tipi di risorse: gestite e non gestite. “Gestito” significa che il runtime ha il controllo della risorsa, mentre “non gestito” significa che è responsabilità del programmatore. E c’è davvero solo un tipo di risorsa gestita che ci interessa in .NET oggi – la memoria. Il programmatore dice al runtime di allocare memoria e dopo di ciò spetta al runtime calcolare quando la memoria può essere liberata. Il meccanismo utilizzato da .NET per questo scopo è chiamato garbage collection e puoi trovare molte informazioni su GC su Internet semplicemente usando Google.

Per gli altri tipi di risorse, .NET non sa nulla di pulirli, quindi deve fare affidamento sul programmatore per fare la cosa giusta. A tal fine, la piattaforma offre al programmatore tre strumenti:

  1. L’interfaccia IDisposable e l’istruzione “using” in VB e C #
  2. finalizzatori
  3. Lo schema IDisposable implementato da molte classi BCL

Il primo di questi consente al programmatore di acquisire in modo efficiente una risorsa, usarla e quindi rilasciarla tutta nello stesso metodo.

 using (DisposableObject tmp = DisposableObject.AcquireResource()) { // Do something with tmp } // At this point, tmp.Dispose() will automatically have been called // BUT, tmp may still a perfectly valid object that still takes up memory 

Se “AcquireResource” è un metodo factory che (ad esempio) apre un file e “Dispose” chiude automaticamente il file, allora questo codice non può perdere una risorsa file. Ma la memoria per l’object “tmp” stesso potrebbe ancora essere allocata. Questo perché l’interfaccia IDisposable non ha assolutamente alcuna connessione con il garbage collector. Se si desidera assicurarsi che la memoria sia stata liberata, l’unica opzione sarebbe chiamare GC.Collect() per forzare una garbage collection.

Tuttavia, non si può sottolineare abbastanza che probabilmente non è una buona idea. In genere è molto meglio lasciare che il garbage collector faccia ciò che è stato progettato per fare, cioè gestire la memoria.

Cosa succede se la risorsa viene utilizzata per un periodo di tempo più lungo, in modo tale che la sua durata di vita superi diversi metodi? Chiaramente, l’istruzione “using” non è più applicabile, quindi il programmatore dovrebbe chiamare manualmente “Dispose” quando ha terminato la risorsa. E cosa succede se il programmatore dimentica? Se non vi è alcun ripiego, il processo o il computer potrebbe esaurire la risorsa che non viene correttamente liberata.

Ecco dove arrivano i finalizzatori. Un finalizzatore è un metodo sulla tua class che ha una relazione speciale con il garbage collector. Il GC promette che – prima di liberare la memoria per qualsiasi object di quel tipo – prima darà al finalizzatore la possibilità di fare una sorta di pulizia.

Quindi, nel caso di un file, teoricamente non è necessario chiudere il file manualmente. Possiamo solo aspettare che il garbage collector arrivi e lasciare che il finalizzatore faccia il lavoro. Sfortunatamente, ciò non funziona in pratica perché il garbage collector funziona in modo non deterministico. Il file potrebbe rimanere aperto molto più a lungo di quanto il programmatore si aspetti. E se vengono mantenuti aperti abbastanza file, il sistema potrebbe non riuscire quando si tenta di aprire un file aggiuntivo.

Per la maggior parte delle risorse, vogliamo entrambe queste cose. Vogliamo che una convention sia in grado di dire “abbiamo finito con questa risorsa ora” e vogliamo assicurarci che ci siano almeno alcune possibilità che la pulizia avvenga automaticamente se ci dimentichiamo di farlo manualmente. È qui che entra in gioco il modello “IDisposable”. Questa è una convenzione che consente a IDispose e un finalizzatore di giocare bene insieme. Puoi vedere come funziona il modello guardando la documentazione ufficiale per IDisposable .

In conclusione : se quello che vuoi veramente fare è semplicemente assicurarti che la memoria sia liberata, quindi IDisposable e finalizzatori non ti aiuteranno. Ma l’interfaccia IDisposable fa parte di un modello estremamente importante che tutti i programmatori .NET dovrebbero comprendere.

È ansible disporre solo di istanze che implementano l’interfaccia IDisposable.

Per forzare un garbage collector a liberare immediatamente la memoria (non gestita):

 GC.Collect(); GC.WaitForPendingFinalizers(); 

Questa è normalmente una ctriggers pratica, ma c’è un bug nella versione x64 del framework .NET, ad esempio, che rende il GC strano in alcuni scenari, e quindi potresti voler farlo. Non so se il bug è stato risolto ancora. Qualcuno sa?

Per disporre una class fai questo:

 instance.Dispose(); 

o in questo modo:

 using(MyClass instance = new MyClass()) { // Your cool code. } 

che tradurrà in fase di compilazione per:

 MyClass instance = null; try { instance = new MyClass(); // Your cool code. } finally { if(instance != null) instance.Dispose(); } 

È ansible implementare l’interfaccia IDisposable in questo modo:

 public class MyClass : IDisposable { private bool disposed; ///  /// Construction ///  public MyClass() { } ///  /// Destructor ///  ~MyClass() { this.Dispose(false); } ///  /// The dispose method that implements IDisposable. ///  public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } ///  /// The virtual dispose method that allows /// classs inherithed from this one to dispose their resources. ///  ///  protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Dispose managed resources here. } // Dispose unmanaged resources here. } disposed = true; } } 

Le risposte a questa domanda sono più che un po ‘confuse.

Il titolo chiede informazioni sullo smaltimento, ma poi dice che vogliono tornare immediatamente alla memoria.

.Net è gestito , il che significa che quando scrivi app .Net non ti devi preoccupare direttamente della memoria, il costo è che non hai nemmeno il controllo diretto sulla memoria.

.Net decide quando è meglio ripulire e liberare memoria, non come coder .Net.

Il Dispose è un modo per dire. Net che hai finito con qualcosa, ma in realtà non libererà la memoria finché non sarà il momento migliore per farlo.

Fondamentalmente. Net raccoglierà effettivamente la memoria quando è più facile farlo – è molto bravo a decidere quando. A meno che tu non stia scrivendo qualcosa che richiede molta memoria, di solito non hai bisogno di sovrascriverlo (questo è parte del motivo per cui i giochi non sono spesso scritti in .Net ancora – hanno bisogno di un controllo completo)

In .Net puoi usare GC.Collect() per forzarlo immediatamente, ma è quasi sempre una ctriggers pratica. Se .Net non lo ha ancora pulito, ciò significa che non è un momento particolarmente favorevole per farlo.

GC.Collect() preleva gli oggetti che .Net identifica come fatto con. Se non hai eliminato un object che ne ha bisogno. Net può decidere di mantenere quell’object. Ciò significa che GC.Collect() è efficace solo se implementi correttamente le istanze disponibili.

GC.Collect() non sostituisce correttamente l’utilizzo di IDisposable.

Quindi, il deposito e la memoria non sono direttamente correlati, ma non è necessario che lo siano. Lo smaltimento corretto renderà le tue app .Net più efficienti e quindi userà meno memoria.


Il 99% delle volte in .Net la seguente è la migliore pratica:

Regola 1: se non gestisci nulla non gestito o che implementa IDisposable , non preoccuparti di Dispose.

Regola 2: se si dispone di una variabile locale che implementa IDisposable, assicurarsi di eliminarla nell’ambito corrente:

 //using is best practice using( SqlConnection con = new SqlConnection("my con str" ) ) { //do stuff } //this is what 'using' actually compiles to: SqlConnection con = new SqlConnection("my con str" ) ; try { //do stuff } finally { con.Dispose(); } 

Regola 3: se una class ha una proprietà o una variabile membro che implementa IDisposable, allora quella class dovrebbe implementare anche IDisposable. Nel metodo Dispose di quella class puoi anche disporre delle tue proprietà IDisposable:

 //rather basic example public sealed MyClass : IDisposable { //this connection is disposable public SqlConnection MyConnection { get; set; } //make sure this gets rid of it too public Dispose() { //if we still have a connection dispose it if( MyConnection != null ) MyConnection.Dispose(); //note that the connection might have already been disposed //always write disposals so that they can be called again } } 

Questo non è veramente completo, ed è per questo che l’esempio è sigillato. Le classi ereditarie potrebbero dover osservare la regola successiva …

Regola 4: se una class utilizza una risorsa non gestita , implementa IDispose e aggiungi un finalizzatore.

.Net non può fare nulla con la risorsa non gestita , quindi ora stiamo parlando di memoria. Se non lo si pulisce, si può verificare una perdita di memoria.

Il metodo Dispose deve gestire sia le risorse gestite che quelle non gestite .

Il finalizzatore è un accorgimento sicuro: garantisce che se qualcun altro crea e un’istanza della class e non riesce a disporne, le risorse non gestite “pericolose” possono ancora essere eliminate da .Net.

 ~MyClass() { //calls a protected method //the false tells this method //not to bother with managed //resources this.Dispose(false); } public void Dispose() { //calls the same method //passed true to tell it to //clean up managed and unmanaged this.Dispose(true); //as dispose has been correctly //called we don't need the //'backup' finaliser GC.SuppressFinalize(this); } 

Finalmente questo sovraccarico di Dispose che prende una bandiera booleana:

 protected virtual void Dispose(bool disposing) { //check this hasn't been called already //remember that Dispose can be called again if (!disposed) { //this is passed true in the regular Dispose if (disposing) { // Dispose managed resources here. } //both regular Dispose and the finaliser //will hit this code // Dispose unmanaged resources here. } disposed = true; } 

Si noti che una volta che tutto ciò è a posto, un altro codice gestito che crea un’istanza della class può semplicemente trattarlo come qualsiasi altro IDisposto (Regole 2 e 3).

Sarebbe opportuno menzionare anche che lo smaltimento non si riferisce sempre alla memoria? Dispongo le risorse come riferimenti ai file più spesso della memoria. GC.Collect () si riferisce direttamente al garbage collector CLR e può o meno liberare memoria (in Task Manager). Probabilmente avrà un impatto negativo sulla tua applicazione (es. Performance).

Alla fine della giornata, perché vuoi tornare immediatamente alla memoria? Se c’è pressione di memoria da qualche altra parte, il sistema operativo ti darà la memoria nella maggior parte dei casi.

Dai un’occhiata a questo articolo

L’implementazione del pattern Dispose, IDisposable e / o un finalizzatore non ha assolutamente nulla a che fare quando viene recuperata la memoria; invece, ha tutto a che fare con il dire al GC come recuperare quella memoria. Quando chiami Dispose () non stai interagendo in alcun modo con il GC.

Il GC funzionerà solo quando determina la necessità di (chiamata pressione di memoria) e quindi (e solo allora) affiderà la memoria per gli oggetti non utilizzati e comprimerà lo spazio di memoria.

Potresti chiamare GC.Collect () ma non dovresti farlo a meno che non ci sia un buon motivo per (che è quasi sempre “Mai”). Quando imponi un ciclo di raccolta fuori banda come questo, in effetti il ​​GC fa più lavoro e alla fine può danneggiare le prestazioni delle tue applicazioni. Per tutta la durata del ciclo di raccolta GC, la tua applicazione è effettivamente in uno stato congelato … più cicli GC vengono eseguiti, più tempo verrà sospeso dall’applicazione.

Ci sono anche alcune chiamate API Win32 native che puoi fare per liberare il tuo working set, ma anche quelle dovrebbero essere evitate a meno che non ci sia un buon motivo per farlo.

L’intera premessa dietro un runtime di gargbage raccolto è che non è necessario preoccuparsi (tanto) di quando il runtime alloca / rilascia la memoria effettiva; devi solo preoccuparti di assicurarti che l’object sappia come ripulire se stesso quando richiesto.

 public class MyClass : IDisposable { public void Dispose() { // cleanup here } } 

allora puoi fare qualcosa di simile

 MyClass todispose = new MyClass(); todispose.Dispose(); // instance is disposed right here 

o

 using (MyClass instance = new MyClass()) { } // instance will be disposed right here as it goes out of scope 

Spiegazione completa di Joe Duffy su ” Smaltimento, finalizzazione e gestione delle risorse “:

In precedenza, nel corso della vita di .NET Framework, i finalizzatori venivano coerentemente definiti come distruttori dai programmatori C #. Man mano che diventiamo più intelligenti nel tempo, stiamo cercando di venire a patti con il fatto che il metodo Dispose è in realtà più equivalente a un distruttore C ++ (deterministico) , mentre il finalizzatore è qualcosa di completamente separato (non deterministico) . Il fatto che C # abbia preso in prestito la syntax del distruttore C ++ (cioè ~ T ()) sicuramente aveva almeno un po ‘a che fare con lo sviluppo di questo termine improprio.

Ho scritto un riassunto di Destructors e Dispose and Garbage collection su http://codingcraftsman.wordpress.com/2012/04/25/to-dispose-or-not-to-dispose/

Per rispondere alla domanda originale:

  1. Non cercare di gestire la tua memoria
  2. Smaltire non riguarda la gestione della memoria, riguarda la gestione delle risorse non gestite
  3. I finalizzatori sono una parte innata del pattern Dispose e rallentano effettivamente la liberazione di memoria degli oggetti gestiti (poiché devono essere inseriti nella coda di Finalization se non già Dispose d)
  4. GC.Collect è danneggiato in quanto rende più lunghi alcuni oggetti a vita breve e quindi li rallenta dalla raccolta.

Tuttavia, GC.Collect potrebbe essere utile se si dispone di una sezione di codice critico per le prestazioni e si desidera ridurre la probabilità che Garbage Collection lo rallenti. Lo chiami prima.

Oltre a questo, c’è un argomento a favore di questo modello:

 var myBigObject = new MyBigObject(1); // something happens myBigObject = new MyBigObject(2); // at the above line, there are temporarily two big objects in memory and neither can be collected 

vs

 myBigObject = null; // so it could now be collected myBigObject = new MyBigObject(2); 

Ma la risposta principale è che la Garbage Collection funziona solo se non si scherza con essa!

Non si può davvero forzare un GC a ripulire un object quando lo si desidera, sebbene esistano modi per forzarlo a funzionare, nulla dice che ripulire tutto l’object che si desidera / si aspetta. È meglio chiamare dispose in un tentativo di cattura, infine, eliminare il modo try end (VB.NET rulz). Ma Dispose serve a ripulire le risorse di sistema (memoria, handle, connessioni db, ecc. Allocate dall’object in modo deterministico. Dispose non ripulisce (e non può) la memoria utilizzata dall’object stesso, solo il GC può farlo

Questo articolo ha una procedura abbastanza semplice. Tuttavia, dover chiamare il GC invece di lasciarlo prendere il suo corso naturale è generalmente un segno di ctriggers progettazione / gestione della memoria, soprattutto se non vengono consumate risorse limitate (connessioni, handle, qualsiasi altra cosa che in genere porta all’implementazione di IDisposable).

Cosa ti causa aver bisogno di fare questo?

L’interfaccia IDisposable è in realtà per le classi che contengono risorse non gestite. Se la tua class non contiene risorse non gestite, perché è necessario liberare risorse prima che il garbage collector esegua? Altrimenti, assicurati solo che il tuo object sia istanziato il più tardi ansible e che vada fuori campo il prima ansible.

Spiacente ma la risposta selezionata qui non è corretta. Come poche persone hanno dichiarato successivamente Smaltire e implementare IDisposable non ha nulla a che fare con la liberazione della memoria associata a una class .NET. È principalmente e tradizionalmente utilizzato per liberare risorse non gestite come handle di file, ecc.

Mentre la tua applicazione può chiamare GC.Collect () per provare a forzare una collezione da parte del garbage collector, ciò avrà davvero un effetto su quegli elementi che sono al livello di generazione corretto nella coda freachable. Quindi è ansible che se hai cancellato tutti i riferimenti all’object potrebbero ancora essere un paio di chiamate a GC.Collect () prima che la memoria effettiva venga liberata.

Non dici nella tua domanda PERCHÉ senti il ​​bisogno di liberare immediatamente la memoria. Capisco che a volte ci possono essere circostanze insolite ma seriamente, nel codice gestito è quasi sempre meglio lasciare che il runtime gestisca la gestione della memoria.

Probabilmente il miglior consiglio se pensi che il tuo codice stia utilizzando la memoria più velocemente di quanto GC lo stia liberando, dovresti rivedere il tuo codice per assicurarti che nessun object che non è più necessario sia referenziato in qualsiasi struttura di dati che hai nei membri statici ecc. Inoltre, cerca di evitare situazioni in cui hai riferimenti ad oggetti circolari poiché è ansible che anche questi non vengano liberati.

@Keith,

Sono d’accordo con tutte le tue regole tranne la # 4. L’aggiunta di un finalizzatore dovrebbe essere eseguita solo in circostanze molto specifiche. Se una class usa risorse non gestite, queste dovrebbero essere ripulite nella funzione Dispose (bool). Questa stessa funzione dovrebbe solo ripulire le risorse gestite quando bool è vero. L’aggiunta di un finalizzatore aggiunge un costo di complessità all’utilizzo dell’object, poiché ogni volta che si crea una nuova istanza, questa deve essere collocata anche nella coda di finalizzazione, che viene controllata ogni volta che il GC esegue un ciclo di raccolta. In pratica, questo significa che il tuo object sopravvive a un ciclo / generazione più a lungo di quanto dovrebbe quindi eseguire il finalizzatore. Il finalizzatore non dovrebbe essere considerato una “rete di sicurezza”.

Il GC eseguirà solo un ciclo di raccolta quando determina che non c’è abbastanza memoria disponibile nell’heap Gen0 per eseguire l’allocazione successiva, a meno che non lo “aiuti” chiamando GC.Collect () per forzare una raccolta fuori banda .

La linea di fondo è che, indipendentemente da cosa, il GC sa solo come rilasciare le risorse chiamando il metodo Dispose (ed eventualmente il finalizzatore se ne viene implementato uno). Spetta a questo metodo “fare la cosa giusta” e ripulire le risorse non gestite utilizzate e istruire qualsiasi altra risorsa gestita a chiamare il loro metodo Dispose. È molto efficiente in ciò che fa e può auto-ottimizzare in larga misura, purché non sia aiutato da cicli di raccolta fuori banda. Detto questo, a meno di chiamare GC.Collect in modo esplicito non si ha il controllo su quando e in quale ordine gli oggetti verranno smaltiti e la memoria rilasciata.

Se non vuoi (o non puoi) implementare IDisposable sulla tua class, puoi forzare la garbage collection in questo modo (ma è lento) –

 GC.Collect(); 

Puoi avere distruzione di oggetti deterministici in c ++

Non si desidera chiamare GC.Collect, ma mette a disagio l’autoconfigurazione del garbage collector per rilevare la pressione della memoria e in alcuni casi non fa altro che aumentare la generazione corrente di ogni object sull’heap.

Per coloro che inviano risposte IDisposable. Chiamare un metodo Dispose non distrugge un object come descritto dal richiedente.

@Keith:

IDisposable è per risorse gestite.

I finalizzatori sono per risorse non gestite.

Scusa ma è solo sbagliato. Normalmente, il finalizzatore non fa nulla. Tuttavia, se il pattern di eliminazione è stato implementato correttamente, il finalizzatore tenta di richiamare Dispose .

Dispose ha due posti di lavoro:

  • Risorse non gestite gratuite e
  • risorse gestite nidificate gratuite.

E qui la tua affermazione entra in gioco perché è vero che, mentre finalizzi, un object non dovrebbe mai provare a liberare risorse gestite annidate in quanto potrebbero essere già state liberate. Deve comunque liberare risorse non gestite.

Tuttavia, i finalizzatori non hanno altro compito che chiamare Dispose e dirgli di non toccare oggetti gestiti. Dispose , quando viene chiamato manualmente (o tramite Using ), libera tutte le risorse non gestite e passa il messaggio Dispose agli oggetti nidificati (e ai metodi della class base) ma questo non libererà mai alcuna memoria (gestita).

Konrad Rudolph – sì, normalmente il finalizzatore non fa nulla. Non dovresti implementarlo a meno che tu non abbia a che fare con risorse non gestite.

Quindi, quando lo realizzi, usi lo schema di smaltimento di Microsoft (come già descritto)

  • public Dispose() chiamate protected Dispose(true) – gestisce sia risorse gestite che risorse non gestite. Calling Dispose() dovrebbe sopprimere la finalizzazione.

  • ~Finalize chiamate protected Dispose(false) – gestisce solo le risorse non gestite. Ciò impedisce perdite di memoria non gestite se non si riesce a chiamare il public Dispose()

~Finalize è lenta e non dovrebbe essere utilizzata a meno che non si disponga di risorse non gestite da gestire.

Le risorse gestite non possono perdere memoria, possono solo sprecare risorse per l’applicazione corrente e rallentare la sua garbage collection. Le risorse non gestite possono perdere e ~Finalize è la procedura migliore per garantire che non lo facciano.

In entrambi i casi l’ using è la migliore pratica.

@Curt Hagenlocher – è di nuovo in testa. Non ho idea del motivo per cui così tanti hanno votato su quando è sbagliato.

IDisposable è per risorse gestite .

I finalizzatori sono per risorse non gestite .

Finché utilizzi solo risorse gestite sia io che Jonj Limjap siamo del tutto corretti.

Per le classi che usano risorse non gestite (e tenete a mente che la stragrande maggioranza delle classi .Net non lo fanno), la risposta di Patrik è completa e buona pratica.

Evita di usare GC.Collect – è un modo lento per gestire le risorse gestite e non fa nulla con quelle non gestite a meno che tu non abbia correttamente costruito i tuoi ~ Finalizzatori.


Ho rimosso il commento del moderatore dalla domanda originale in linea con https://stackoverflow.com/questions/14593/etiquette-for-modifying-posts

In risposta alla domanda originale, con le informazioni fornite finora dal poster originale, è certo al 100% che non ne sappia abbastanza sulla programmazione in .NET per ricevere una risposta: utilizzare GC.Collect (). Direi che è del 99,99% probabilmente che non ha davvero bisogno di usare GC.Collect () affatto, come ha sottolineato la maggior parte dei posters.

La risposta corretta si riduce a “Lascia che il GC faccia il suo lavoro. Periodo. Hai altre cose di cui preoccuparti. Ma potresti decidere se e quando smaltire o ripulire oggetti specifici e se è necessario implementare IDisposable e possibilmente Finalize nella tua class. ”

Per quanto riguarda il post di Keith e la sua regola n. 4:

Alcuni poster confondono la regola 3 e la regola 4. La regola 4 di Keith è assolutamente corretta, inequivocabilmente. È l’unica regola dei quattro che non richiede alcuna modifica. Vorrei riformulare leggermente alcune delle sue altre regole per renderle più chiare, ma sono sostanzialmente corrette se le analizzi correttamente e in realtà leggi l’intero post per vedere come si espande su di loro.

  1. Se la tua class non usa una risorsa non gestita E inoltre non crea mai un’istanza di un altro object di una class che utilizza, direttamente o alla fine, un object non gestito (cioè una class che implementa IDisposable), quindi non ci sarebbe bisogno della tua class sia implementare IDisposable stesso, o anche chiamare .dispose su qualsiasi cosa. (In tal caso, è sciocco pensare che sia effettivamente NECESSARIO liberare immediatamente la memoria con un GC forzato, comunque).

  2. Se la tua class utilizza una risorsa non gestita, OR crea un’istanza di un altro object che implementa IDisposable, allora la tua class dovrebbe:

    a) dispose / rilascialo immediatamente in un contesto locale in cui sono stati creati, OPPURE …

    b) implementare IDisposable nel modello raccomandato all’interno del post di Keith, o qualche migliaio di posti su internet, o in letteralmente circa 300 libri ormai.

    b.1) Inoltre, se (b), ed è una risorsa non gestita che è stata aperta, entrambi IDisposable AND Finalize DEVONO SEMPRE essere implementati, secondo la regola # 4 di Keith.
    In questo contesto, Finalize è assolutamente una rete di sicurezza in un certo senso: se qualcuno crea un’istanza dell’object IDisposable che utilizza una risorsa non gestita e non riescono a chiamare dispose, Finalize è l’ultima possibilità per il tuo object di chiudere correttamente la risorsa non gestita.
    (Finalize dovrebbe farlo chiamando Dispose in modo tale che il metodo Dispose salti oltre il rilascio di qualcosa MA la risorsa non gestita. In alternativa, se il metodo Dispose dell’object è chiamato correttamente da qualsiasi object istanziato, allora ENTRAMBI passa la chiamata Dispose a tutti gli oggetti idisposabili che ha istanziato, E rilascia correttamente le risorse non gestite, terminando con una chiamata per sopprimere Finalize sul proprio object, il che significa che l’impatto dell’utilizzo di Finalize si riduce se l’object è disposto correttamente dal chiamante. sono inclusi nel post di Keith, BTW.)

    b.2) SE la tua class sta implementando solo IDisposable perché deve essenzialmente passare su Dispose a un object IDisposable che ha istanziato, quindi non implementare un metodo Finalize nella tua class in quel caso. Finalizza è per la gestione del caso che BOTH Dispose non è mai stato chiamato da qualsiasi istanza del tuo object, E una risorsa non gestita è stata utilizzata che è ancora inedita.

In breve, per quanto riguarda il post di Keith, è completamente corretto, e quel post è la risposta più corretta e completa, secondo me. Può usare alcune affermazioni a mano breve che alcuni trovano “sbagliato” o object, ma il suo post completo si espande completamente sull’uso di Finalize, ed è assolutamente corretto. Assicurati di leggere il suo post completamente prima di saltare su una delle regole o dichiarazioni preliminari nel suo post.

Se MyClass implementa IDisposable, puoi fare proprio questo.

 MyClass.Dispose(); 

Le migliori pratiche in C # sono:

 using( MyClass x = new MyClass() ) { //do stuff } 

Come quello avvolge il dispose in un tentativo-finalmente e si assicura che non sia mai mancato.