como - destructores c#
¿Por qué invocar dispose(false) en el destructor? (6)
Lo que sigue es un típico ejemplo de patrón de disposición:
public bool IsDisposed { get; private set; }
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!IsDisposed)
{
if (disposing)
{
//perform cleanup here
}
IsDisposed = true;
}
}
~MyObject()
{
Dispose(false);
}
Entiendo lo que hace disponer, pero lo que no entiendo es por qué querría llamar a disponer (falso) en el destructor. Si nos fijamos en la definición, no haría absolutamente nada, entonces ¿por qué alguien escribiría un código como este? ¿No tendría sentido simplemente no llamar a disponer del destructor?
"La idea aquí es que Dispose (Boolean) sabe si se lo está llamando para hacer una limpieza explícita (el Boolean es verdadero) versus ser llamado debido a una recolección de basura (el Boolean es falso). Esta distinción es útil porque, cuando se elimina explícitamente, el método Dispose (Boolean) puede ejecutar código de forma segura usando campos de tipo de referencia que hacen referencia a otros objetos sabiendo con certeza que estos otros objetos aún no han sido finalizados o eliminados. Cuando Boolean es falso, el método Dispose (Boolean) debería no ejecutar código que se refiera a campos de tipo de referencia porque esos objetos ya pueden haber sido finalizados ".
Hay mucha más información en las "Pautas de diseño de gestión de recursos, eliminación y finalización" .
Editar: enlace.
Creo que la confusión se debe al hecho de que en su ejemplo no está liberando ningún recurso no administrado. También deben liberarse cuando se solicite el disposing
través de la recolección de basura y se liberarían fuera del cheque para su disposing
. Consulte el ejemplo de MSDN relacionado con la liberación de recursos no administrados . El otro que eso / debería ocurrir fuera del cheque es una llamada a cualquier método de eliminación de la clase base.
Del artículo citado:
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Release managed resources.
}
// Release unmanaged resources.
// Set large fields to null.
// Call Dispose on your base class.
base.Dispose(disposing);
}
Dentro del if (desechar) se supone que debe llamar a dispose / close en objetos gestionados que tienen recursos no administrados (por ejemplo, conexiones de base de datos). Cuando se llama al finalizador, estos objetos ya no son accesibles para que los objetos mismos puedan finalizarse y usted no necesita llamar a disponer de ellos. Además, el orden de finalización no está terminado, por lo que puede estar llamando a deshacerse de los objetos ya dispuestos.
El finalizador se usa como un retroceso si el objeto no se elimina adecuadamente por algún motivo. Normalmente se llamará al método Dispose()
que elimina la conexión del finalizador y convierte el objeto en un objeto gestionado normal que el recolector de basura puede eliminar fácilmente.
Aquí hay un ejemplo de MSDN de una clase que tiene recursos administrados y no administrados para limpiar.
Tenga en cuenta que los recursos administrados solo se limpian si la disposing
es verdadera, pero los recursos no administrados siempre se limpian.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user''s code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
El siguiente ejemplo muestra cómo crear una clase de recurso que implemente la interfaz IDisposable: https://msdn.microsoft.com/en-us/library/System.IDisposable.aspx
En la función Dispose (disposición de bool): si la eliminación es igual a verdadera, el código ha llamado directa o indirectamente al método. Los recursos administrados y no administrados pueden ser eliminados. Si disponer es igual a falso, el tiempo de ejecución ha llamado al método desde el finalizador y no debe hacer referencia a otros objetos. Solo los recursos no administrados pueden ser eliminados.
No hay destructores en C #. Eso es un Finalizer, que es algo diferente.
La distinción es si necesita limpiar objetos administrados o no. No desea intentar limpiarlos en el finalizador, ya que ellos mismos pueden haber sido finalizados.
Recientemente, recientemente miré la página Destructors de la Guía de programación de C #. Muestra que estaba equivocado en mi respuesta, arriba. En particular, hay una diferencia entre destructor y finalizador:
class Car
{
~Car() // destructor
{
// cleanup statements...
}
}
es equivalente a
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}