2013-05-17 10 views
15

In this answer ho trovato,Dispose() per la pulizia delle risorse gestite?

Cleanup le risorse non gestite nel metodo Finalize e quelli gestiti nel metodo Dispose, quando il Dispose/Finalizzazione modello è stato utilizzato nel codice.

E successivamente ho trovato this nice article sul finalizzare e smaltire e ho avuto una chiara idea su di loro. L'articolo ha il seguente codice (Page 3), per spiegare i concetti:

class Test : IDisposable 
{ 
    private bool isDisposed = false; 

    ~Test() 
    { 
     Dispose(false); 
    } 

    protected void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      // Code to dispose the managed resources of the class 
     } 
     // Code to dispose the un-managed resources of the class 

     isDisposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
} 

Ma sotto che appare, la stessa nota (che ho inserito all'inizio di questa domanda).

Il modello Dispose/Finalize Microsoft consiglia di implementare sia Dispose che Finalize quando si lavora con risorse non gestite. La sequenza corretta quindi sarebbe essere per uno sviluppatore per chiamare Dispose. L'implementazione di Finalize eseguirà e le risorse verranno comunque rilasciate quando l'oggetto è immondizia raccolta anche se uno sviluppatore non ha richiamato esplicitamente il metodo Dispose . Francesco Balena scrive nel suo blog "lo schema Dispose/Finalize deve essere utilizzato solo quando il tuo tipo invoca il codice non gestito che alloca le risorse non gestite (inclusa la memoria non gestita) e restituisce un handle che è necessario utilizzare per rilasciare la risorsa . disporre e finalizzare deve associare gli oggetti parentali chiamando i rispettivi metodi dei genitori dopo aver eliminato o finalizzato i propri membri " ". In poche parole, ripulisci le risorse non gestite nel metodo Finalize e quelle gestite nel metodo Dispose, quando il codice Dispose/Finalize è stato utilizzato nel codice.

Ora sono di nuovo confuso. Nell'intero articolo e nell'esempio di codice, viene mostrato che le risorse non gestite devono essere liberate in Dispose(). Ma allora qual è la rilevanza di quel commento?

Edit:

Come si conferma che questa linea:

In poche parole, la pulizia le risorse non gestite nel metodo Finalize e quelli gestiti nel metodo Dispose, quando il Dispose/Finalizzazione modello è stato utilizzato nel codice

è erronea, ho modificato this answer.

risposta

30

Vedere il suo molto semplice.

  1. Se avete a che fare con le risorse non gestite - implementare sia Smaltire e Finalizza.Dispose deve essere chiamato dagli sviluppatori per liberare le risorse non appena le vedono che non è più necessario per loro. Se si dimenticano di chiamare Dispose, allora Framework chiama il finalize nel proprio ciclo di GC (di solito prenderà il suo tempo dolce).
  2. Se non si ha a che fare con risorse non gestite - Quindi non fare nulla. Non implementare Finalize né Dispose.
  3. Se l'oggetto utilizza gli oggetti monouso internamente - Si implementa Dispose() se è stato creato e mantenuto un riferimento a qualsiasi oggetto di un tipo che implementa Dispose() e che non è già stato eliminato.

Alcuni esempi classici:

System.IO.FileStream oggetto gestisce il blocco/flusso di maniglie per i file. Quindi implementa sia dispose che finalizzate. Se lo sviluppatore lo dispone, l'altro programma può accedervi immediatamente. Se si dimentica di eliminarlo, il Framework lo finalizza e chiude le maniglie in un secondo momento nel suo ciclo di GC.

System.Text.StringBuilder dose non ha alcuna risorsa non gestita. Quindi non disporre nulla di finalizzato.

Per quanto riguarda il modello è interessato che cosa significa
// Code to dispose the managed resources of the class
è che chiamare i metodi lo smaltimento di un oggetto .NET che avete come componenti all'interno di quella classe

E

// Code to dispose the un-managed resources of the class mezzi per chiudi le maniglie e i puntatori grezzi. Ecco il codice aggiornato con esempi

class Test : IDisposable 
    { 
    private bool isDisposed = false; 

    ~Test() 
    { 
     Dispose(false); 
    } 

    protected void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
     // Code to dispose the managed resources of the class 
     internalComponent1.Dispose(); 
     internalComponent2.Dispose(); 
     } 

     // Code to dispose the un-managed resources of the class 
     CloseHandle(handle); 
     handle = IntPtr.Zero; 

     isDisposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
    } 

Ecco una vecchia questione explaing si http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/186947fd-e6da-41fb-9998-3b1e6223f17c

+0

In realtà non esiste alcuna pulizia delle risorse gestite. Non vedo il suo punto in alcun modo pertinente. Il massimo che puoi fare per pulire una risorsa gestita è assegnarlo a NULL. Il che è del tutto superfluo con un GC così buono. –

+0

Questo è un articolo scritto nel 2006, quindi non mi preoccuperei più di tanto. –

+2

Non è così semplice. Dovresti anche implementare 'Dispose()' se hai creato e mantenuto un riferimento a * qualsiasi * oggetto di un tipo che implementa 'Dispose()' e che non hai ancora eliminato. Alcuni tipi non utilizzano risorse non gestite ma hanno cose come sottoscrizioni di eventi che devono essere sganciate nei loro metodi 'Dispose()'. È necessario disporre di tali oggetti ANCHE SE NON si utilizzano risorse non gestite, altrimenti è possibile che si verifichi una perdita di memoria. Questo è spesso particolarmente vero per le classi UI derivate da 'Control' o' UserControl'. –

3

Se un Foo ha risorse che beneficeranno di pulitura deterministica, ma nessuno che può essere utilmente ripulito in un finalizzatore, è dovrebbe implementare IDisposable ma non dovrebbe sostituire lo Finalize o avere un distruttore. Se una classe contiene più risorse e almeno una può essere ripulita in un finalizzatore, allora ciascuna risorsa discreta che può essere ripulita in un finalizzatore dovrebbe essere incapsulata nel proprio oggetto Finalizzatore/distruttore (che può essere definito in un classe nidificata protetta) e la classe che conterrebbe tali risorse dovrebbe contenere riferimenti agli oggetti wrapper. Una volta fatto, la classe esterna si adatta al modello per le classi con un metodo Dispose ma nessun finalizzatore/distruttore.