net - finalize c#
Dos preguntas sobre Dispose() y destructores en C# (3)
Tengo una pregunta sobre cómo usar Dispose()
y destructores. Al leer algunos artículos y la documentation MSDN, esta parece ser la forma recomendada de implementar Dispose()
y los destructores.
Pero tengo dos preguntas sobre esta implementación, que puedes leer a continuación:
class Testing : IDisposable
{
bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!_disposed) // only dispose once!
{
if (disposing)
{
// Not in destructor, OK to reference other objects
}
// perform cleanup for this object
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
// tell the GC not to finalize
GC.SuppressFinalize(this);
}
~Testing()
{
Dispose(false);
}
}
GC.SupressFinalize (this) en Dispose ()
Cuando el programador usa o llama a Dispose () explícitamente, nuestra clase está llamando a GC.SupressFinalize(this)
. Mi pregunta aquí es:
- ¿Qué significa esto exactamente? ¿Se recogerá el objeto pero sin llamar al destructor? Supongo que la respuesta es sí, ya que el framework convierte los destructors en una llamada Finalize (), pero no estoy seguro.
Finalizando sin una llamada Dispose ()
Supongamos que el GC va a limpiar nuestro objeto pero el programador no llamó a Dispose()
- ¿Por qué no disponemos de recursos en este punto? En otras palabras, ¿por qué no podemos liberar recursos en destructor?
¿Qué código se debe ejecutar en el interior, y qué fuera?
if (!_disposed) // only dispose once! { if (disposing) { //What should I do here and why? } // And what here and why? }
Gracias por adelantado
1. ¿Qué hace SuppressFinalize?
Anula el registro del objeto de la lista de finalizadores, es decir, cuando el GC recopila el objeto más adelante, ignorará la presencia del destructor. Esta es una gran ganancia en el rendimiento, ya que el destructor requeriría que la colección del objeto, y la de todo lo que hace referencia, se retrase.
2. ¿Por qué no disponemos de recursos [gestionados] en este momento? En otras palabras, ¿por qué no podemos liberar recursos [gestionados] en destructor?
Podría, pero es seguro que no tiene sentido: el objeto en el que se encuentra se ha vuelto inalcanzable, por lo que todos los recursos administrados que son propiedad de él también son inalcanzables. El CG los finalizará y recopilará en la misma ejecución y llamar a Dispose () en ellos es innecesario pero no totalmente sin riesgo ni costo.
2a ¿Qué código debe ejecutarse en el interior y si fuera?
Dentro de if(disposing)
, llame a _myField.Dispose()
En otras palabras, disponer de recursos administrados (objetos con una disposición)
Fuera, llame al código para limpiar (cerrar) recursos no administrados , como Win32API.Close(_myHandle)
.
Tenga en cuenta que cuando no tiene recursos no administrados, como suele ser el caso (busque SafeHandle), no necesita un destructor y, por lo tanto, no tiene SuppressFinalize.
Y eso hace que la implementación completa (oficial) de este patrón solo sea necesaria debido a la posibilidad de que Test se herede de.
Tenga en cuenta que el Dispose(bool)
está protegido. Cuando declara que su Prueba de clase está sealed
, es totalmente seguro y conforme a omitir la ~Testing()
.
La gran mayoría de las veces cuando se finaliza un objeto que posee recursos IDisposable
, al menos una de las siguientes declaraciones se aplicará a cada uno de esos recursos:
- Ya se ha finalizado, en cuyo caso no es necesario realizar ninguna limpieza.
- Su finalizador aún no se ha ejecutado, pero está programado para hacerlo, en cuyo caso no es necesaria la limpieza.
- Solo se puede limpiar dentro de un hilo en particular (que no es el hilo finalizador), en cuyo caso el hilo finalizador no debe intentar limpiarlo.
- Puede que otra persona lo esté utilizando, en cuyo caso el hilo finalizador no debe intentar limpiarlo.
En algunas de las raras circunstancias donde no se aplica nada de lo anterior, la limpieza dentro del finalizador puede ser apropiada, pero uno no debería considerarla a menos que primero haya examinado las cuatro posibilidades anteriores.
Primera parte:
Cuando se GC.SupressFinalize(this)
, se le informa a GC que el objeto ya ha liberado sus recursos y se puede recolectar como cualquier otro objeto. Y sí, la finalización y los "destructores" son lo mismo en .NET.
Segunda parte:
La finalización se realiza mediante un subproceso independiente y no tenemos control sobre el tiempo y el orden de finalización, por lo que no sabemos si hay otros objetos disponibles o si ya están finalizados. Por este motivo, no puede hacer referencia a otro objeto fuera del bloque de disposing
.