2010-10-07 10 views
5

Según la documentación (MSDN: link), está claro que se debe usar el patrón IDisposable al implementar un finalizador.Finalizador e IDisposable

Pero, ¿necesita implementar un finalizador si implementa IDisposable (para proporcionar una forma determinista de deshacerse del objeto), y no tiene ningún recurso no administrado para limpiar?

Como yo lo veo, si la clase solo tiene recursos administrados y si no llama a Dispose, los recursos gestionados se limpiarán automáticamente por el GC y, por lo tanto, no es necesario implementar el finalizador. ¿Me equivoco?

Además, ¿qué sucede si estoy utilizando mi método Dispose para limpiar los controladores de eventos. Como Dispose no será llamado automáticamente por el GC, ¿debería implementar un Finalizer para asegurarme de que los manipuladores de eventos no estén conectados?

+0

Basado en todos los comentarios, escribí una publicación en el blog sobre este tema: http://blog.aggregatedintelligence.com/2010/10/idposable-and-finalizers.html –

+0

Se escribió mucha información sobre los finalizadores antes del SafeHandle clase fue agregada a .Net 2.0. Puede ser bueno seguir el patrón Dispose, ya que las personas que mantengan su código en el futuro pueden esperarlo, pero muy pocas clases deberían tener finalizadores, y no puedo pensar en * cualquier * caso donde una clase derivada de una base no trivial debería tener un finalizador A menos que uno use alguna magia arcana, los finalizadores no harán nada útil con los eventos; Los eventos colgantes evitarán que se ejecute un finalizador a menos que o hasta que las circunstancias hagan que su limpieza sea irrelevante. – supercat

Respuesta

7

No, no necesita implementar un finalizador si tiene una clase que implementa IDisposable (es decir, si ha implementado el patrón correctamente y si solo tiene recursos gestionados para deshacerse de él). (si lo hace, puede afectar la vida útil de su objeto, ya que los objetos con finalizadores se agregan a la cola de finalización en el GC y pueden vivir más de lo necesario; esto puede ser un problema si sus objetos son grandes.)

+0

Su respuesta contradice la respuesta de SLaks, entonces, ¿quién tiene razón? –

+0

@Rajah: Nuestras respuestas no contradicen. Sin embargo, tengo razón; vea http://msdn.microsoft.com/en-us/library/ms244737%28v=VS.100%29.aspx y http://msdn.microsoft.com/en-us/magazine/cc163324.aspx – SLaks

+0

@ Rajah: Las respuestas no contradicen. Respondí a su pregunta: "¿necesita implementar un finalizador si implementa IDisposable ... y no tiene ningún recurso no administrado para limpiar?". La respuesta es que no es necesario. – adrianbanks

7

No debe agregar un finalizador a menos que tenga recursos no administrados.

Una clase que posee recursos desechables administrados pero no recursos no administrados debe implementar el patrón completo Dispose, pero no tener un finalizador.

Si la clase no es sealed, debe llamar al GC.SuppressFinalize(this) en su método Dispose() en caso de que una clase heredada agregue un finalizador.

+1

¿Y si esa clase heredada también agrega un recurso no administrado? –

+0

@Henk: Es por eso que agregaría un finalizador. (Y anular 'Dispose (bool)') – SLaks

+0

Todavía no veo por qué una clase base Dispose debería interferir con SupressFinalize. Si lo hace, un Dispose derivado no puede llamar de manera segura a base.Dispose(). –

0

Si solo tiene recursos administrados, entonces no necesita implementar IDisposable en absoluto. IDisposable está destinado a limpiar cosas que están más allá del dominio del GC, como identificadores nativos, conexiones de bases de datos, etc.

Si su control contiene controles que implementan IDisposable y deben liberar recursos nativos, entonces todavía necesita implementar el patrón IDisposable y dele a sus hijos controles la oportunidad de deshacerse de ellos.

La razón para llamar a Dispose() en el finalizador es, como último recurso, si el objeto no se desechó correctamente, el GC lo hará como un último esfuerzo.

+0

Falta el caso en que su clase contiene referencias a recursos administrados que implementan IDisposable. Entonces deberías tener un Dispose que llame a Dispose en estos objetos –

+0

@Isak I abordado en el párrafo dos. –

+0

Ok, ya lo veo. Sin embargo, su primer párrafo es un poco engañoso: considero que una clase que implementa Idisposable debe ser administrada. –

0

Sí, si sólo han conseguido recursos, que serán limpiadas por la GC cuando se produce recolección de basura (y no hay ninguna referencia de vida que apuntan a ellos)

Pero en este caso, ¿por qué ¿Necesitas implementar IDisposable en tu tipo? Quiero decir, parece que considera que en su caso, no deshacerse de su objeto no es un gran problema, entonces ¿por qué alguien los descartaría?

También debe tener en cuenta que existe una penalidad de rendimiento con la recolección de elementos no utilizados durante el uso de Finalizer: cualquier objeto con un finalizador escapará al primer pase de GC, lo que degradará bastante la eficacia del GC si estos objetos son de corta duración.

Durante la primera recolección de elementos no utilizados durante la cual se debe limpiar el objeto, no lo hará, para ejecutar el finalizador. El objeto se considerará como larga vida por el GC, incluso si ya debe ser limpiado.

0

Nunca tuve la necesidad de implementar un finalizador. Como saben, le da al objeto la oportunidad de hacer lo que sea necesario antes de GC. Todos los recursos deben ser liberados en el método dispose

+1

Los recursos no administrados deben ser limpiados por el finalizador (y Eliminar, vea el patrón) – SLaks

+0

Correcto ... lo siento, asumí que no se administró ... –

+0

errr Managed., .. –

2
  1. No, estás en lo correcto, si el objeto contiene un objeto que tiene un recurso no administrado entonces usted debe aplicar IDisposable para que pueda llamar su botar en su botar, pero no necesita un finalizador ya que su finalizador se ocupará de ese asunto.

  2. De hecho, tratar de hacer cualquier cosa con un miembro finalizable en un finalizador es precario, y el orden en que se ejecutarán los finalizadores no es determinista, por lo que puede obtener algunos errores desagradables si intenta hacer esto.

  3. Como regla, es mucho mejor tener una clase que contenga 1 o 0 recursos no administrados. Y si tiene 1 recurso no administrado, debería tener tan poco otro estado como sea necesario para manejarlo (es decir, ningún otro miembro desechable). SafeHandle es una buena forma de lidiar con esto. Si una clase necesita tratar varios recursos no administrados, debe hacerlo mediante el manejo de dichos recursos a través de estas clases de controladores. Entonces un finalizador & IDisposable se vuelve fácil; o bien tiene el único recurso no gestionado para tratar en ambos (suprime el finalizador si se llama a disponer) o solo necesita IDisposable.

Debido a tener que lidiar con los recursos no administrados directamente es relativamente raro, lo más probable es que usted nunca tendrá que escribir una finaliser (creo que lo he hecho una vez, en el código real). Debido a que las personas sensatas no hacen mucho más en las clases que manejan recursos no administrados, el asunto Dispose (bool) es innecesario también.