c# - personalizar - tooltip visual studio
¿Cuándo dice CLR que un objeto tiene un finalizador? (4)
Sé que en C #, si escribes ~MyClass()
, esto se traduce básicamente para override System.Object.Finalize()
. Entonces, ya sea que escriba el destructor o no, cada tipo en CLR tendrá un método Finalize()
(al menos de System.Object
).
1] Entonces, ¿significa que, cada objeto, por defecto, tiene un finalizador?
2] ¿Cuál es la base para que el CLR decida que un objeto debe pasar por la cola de finalización?
Me estoy preguntando esto, porque, tenía una clase, decía ManagedResourceHolder
que implementaba IDisposable
, pero no llamaba a GC.SuppressFinalize(this)
en su método IDisposable.Dispose()
. La clase no ~ManagedResourceHolder()
ningún recurso no administrado, y no era necesario el ~ManagedResourceHolder()
, lo que a su vez significaba que no era necesario GC.SuppressFinalize(this)
ya que no había un finalizador .
3] En el contexto del escenario anterior, ¿ siempre es necesario proporcionar un finalizador cuando implemente IDisposable? (incluso en una clase que no contiene recursos no administrados)
La regla CA1816 de FxCop me estaba infringiendo esto y la respuesta que obtuve aquí cuando pregunté en el foro de CA en MSDN me confundió.
Gracias.
- No, no significa eso. Solo
Finalize()
reemplazado será contado por el CLR. - Al tener un finalizador, como se define arriba.
- No, no siempre es necesario. Es solo un buen patrón. Quiero decir, nadie te obliga a hacerlo. Pero es algo bueno que hacer si tiene recursos no administrados, ya que si alguien olvida deshacerse de él, el recurso no administrado se liberará en algún momento. FxCop no aplica reglas estrictas. Impone buenos patrones que pueden llevar al fracaso en el futuro si no se cuida.
ACTUALIZACIÓN: cada clase es responsable de administrar sus propios recursos. Debido a las características de abstracción y encapsulación de los paradigmas orientados a objetos, el consumidor de una clase no debería preocuparse por los recursos que posee, de forma indirecta. Por lo tanto, debe liberar manualmente los recursos que posee (lo que posee es lo que posee directamente cuando mira otras cosas como una caja negra ) o dejar que el GC lo libere. Para recursos no administrados, no tiene la opción de dejarlo en el GC, por lo que debe liberarlo manualmente. En este sentido, un SafeHandle que Jon mencionó es una abstracción gestionada de un recurso no gestionado , por lo tanto, debe tratarse como un recurso gestionado valioso (que es un recuadro negro que gestiona la finalización de ese recurso no gestionado).
1) Sí (en virtud de la herencia)
2) Nada contiene una referencia a la instancia de una clase (que lo hará elegible para la finalización)
3) Sí (¿por qué debería uno implementar IDisposable a menos que requiera que el usuario haga una invocación explícita?) Las clases de conexión en .net usan un recurso umanaged bajo el capó y si no llama a disponer de él, se mantendrá en él. Como el tiempo de GC es desconocido, la conexión permanecerá abierta hasta ese momento)
Este es mi entendimiento.
Podría estar equivocado. En ese caso, los expertos me corregirán las cosas.
1: solo cuenta realmente (en el sentido útil) si ha sido anulado
2: como se define por 1, y GC.SuppressFinalize no se ha llamado (más volver a registrarse, etc.)
3: ciertamente no; de hecho, a menos que esté manejando directamente un recurso no administrado, no debería tener un finalizador. No debe agregar un finalizador solo porque es IDisposable, pero las cosas que tienen finalizadores también deberían ser IDisposables.
Preguntas 1 y 2 : El CLR básicamente verifica si el finalizador es anulado o no. Si no es así, lo trata como si no tuviera un finalizador.
El beneficio de tener un finalizador en System.Object es que los compiladores saben que siempre pueden poner una llamada a base.Finalize()
in. Esto evita problemas de versionado. Considere un mundo sin System.Object.Finalize()
:
- System.Object (no Finalize)
- Acme.BaseClass (sin finalizar)
- MyCompany.DerivedClass (Finalize)
Sin un método Finalize
en objeto, el finalizador en MyCompany.DerivedClass no puede llamar a nada. Lo que lleva a un problema cuando la versión 2 de Acme.BaseClass sale con un finalizador. A menos que recompile MyCompany.DerivedClass, una instancia de DerivedClass se finalizará sin llamar a BaseClass.Finalize, que es claramente una cosa mala.
Ahora considere la misma situación con System.Object.Finalize: el compilador inserta una llamada a base. Finalice automáticamente en DerivedClass.Finalize, que en la versión 1 simplemente llama a la implementación no operativa en System.Object. Cuando sale la versión 2 de Acme.BaseClass, la llamada a base.Finalize
(llamada sin recopilación de DerivedClass) llama a BaseClass.Finalize.
Pregunta 3 : No, no necesita tener un finalizador solo porque implementa IDisposable. Los finalizadores solo deben usarse para recursos no administrados que nada más va a limpiar , es decir, aquellos a los que tiene una referencia directa . Por ejemplo, supongamos que tiene una clase que tiene una variable de miembro de FileStream
. Desea implementar IDisposable
para que pueda cerrar la transmisión tan pronto como sea posible, si la persona que llama recuerda, pero si no recuerda llamar a Dispose()
, la transmisión será elegible para la recolección de basura al mismo tiempo que su objeto. Confíe en que FileStream
tiene un finalizador apropiado (o una referencia a otra cosa con un finalizador, etc.) en lugar de tratar de limpiarlo en su propio finalizador.
A partir de .NET 2.0, con la clase SafeHandle , debería ser increíblemente raro que necesites tu propio finalizador.