2009-03-07 6 views

risposta

9

C'è sempre un finalizzatore in IL - System.Object.Finalize() esiste in ogni classe, quindi, se si effettua una classe personalizzata, ha un finalizzatore si desidera eliminare. Detto questo, non tutti gli oggetti vengono messi nella coda di finalizzazione, quindi solo tecnicamente dovrebbe essere necessario sopprimere la finalizzazione se si implementa il proprio finalizzatore.

Se si sta implementando IDisposable per racchiudere le risorse non gestite, è necessario includere un finalizzatore e si dovrebbe impedire l'esecuzione, poiché in teoria si sta già facendo la pulizia quando viene chiamato Dispose.

+0

Vero. Inoltre, dovresti avere un finalizzatore che chiami Dispose(). – configurator

+0

True- Object.Finalize è un'opzione nulla, ma se stai implementando IDisposable, stai dicendo che hai risorse da liberare. Da MSDN, ciò significa che devi sempre avere un finalizzatore per liberarli, quindi vengono gestiti correttamente. Ciò significa avere Finalize call Dispose, e Dispose sopprimere la finalizzazione –

+4

@configurator Si dovrebbe avere un finalizzatore solo se si possiedono risorse non gestite direttamente (come handle). Se li possiedi solo indirettamente, ad es. un riferimento a un FileStream, perché dovresti scrivere qualcosa di più di IDisposable.Dispose() {if (fs! = null) {fs.Dispose(); fs = null; }}? IMO, StyleCop è uno strumento terribile che costringe MOLTO testo inutile a essere scritto e mantenuto, e in cambio non aggiunge alcun valore aziendale. –

2

Tutti gli oggetti hanno un metodo di finalizzazione, anche se non ne è stato implementato uno utilizzando un distruttore C# (che in realtà non è garantito essere chiamato dal GC). È solo una buona pratica sopprimere la chiamata se hai implementato IDisposable perché ciò significa che hai deciso di eseguire esplicitamente la finalizzazione.

devx article

+0

Potresti spiegare "non è garantito che venga chiamato dal GC"? –

+0

Durante la chiusura del programma, alcuni oggetti potrebbero non avere la possibilità di eseguire i finalizzatori se la pulizia richiede troppo tempo. Questo potrebbe essere ciò a cui si sta riferendo. –

+0

Sì, questo è quello a cui mi riferivo. – x0n

2

Non vedo alcuna necessità di chiamare SuppressFinalize() se non è definito alcun finalizzatore. Se si desidera essere difensivi, può essere utile disporre di un finalizzatore e di Dispose(), quindi non è necessario affidarsi ai client per chiamare sempre Dispose(). Quindi non perderai risorse quando dimenticheranno.

+0

Se un oggetto è "responsabile" per altri oggetti, IDisposable, ma non ha risorse non gestite da solo, allora ha bisogno di Dispose ma non di Finalizer. –

20

Non c'è bisogno di chiamare GC.SuppressFinalize(this) in Dispose, a meno che:

  • Tu sei la classe base che implementa i metodi virtuali Dispose destinati per superiori (di nuovo, potrebbe non essere la vostra responsabilità anche qui, ma si potrebbe desiderare per farlo in quel caso)
  • Hai un finalizzatore tu stesso. Tecnicamente, ogni classe in .NET ha un finalizzatore, ma se l'unico finalizzatore presente è quello di Object, allora l'oggetto non viene considerato necessario mettere a punto e non è messo nella lista messa a punto su GC

I direi, supponendo che tu non abbia nessuno dei casi sopra elencati, puoi tranquillamente ignorare quel messaggio.

+1

Quando una classe derivata * EVER * aggiunge un finalizzatore a una classe base non banale? Perché aggiungere codice per consentire a una classe derivata di fare qualcosa che non dovrebbe mai fare? – supercat

+0

@supercat Se una classe derivata possiede risorse non gestite, dovrebbe avere un finalizzatore per assicurarsi che vengano liberate. Se l'oggetto è sempre usato correttamente (con un try-finally o, equivalentemente, un'istruzione using), Dispose eseguirà la pulizia e sopprimerà il finalizzatore, ma il finalizzatore assicura che le risorse non gestite vengano liberate alla fine (quando l'oggetto è garbage collector), anche se Dispose non è mai stato chiamato (ad esempio a causa di un'eccezione e la mancata protezione di un blocco di codice). –

+1

@ TheDag: ogni risorsa non gestita che richiede la pulizia del finalizzatore dovrebbe quasi sempre essere incapsulata all'interno del proprio oggetto che dovrebbe derivare da 'Object' o un tipo di base astratto esplicitamente progettato per facilitare tale pulizia. Il tipo risultante sarebbe quindi una risorsa gestita, a cui un riferimento potrebbe essere considerato dal tipo più grande. La pulizia della finalizzazione sarebbe gestita dall'oggetto incapsulante più piccolo; l'oggetto più grande non avrebbe bisogno di un finalizzatore. – supercat