method - idisposable implementation example c#
Dispose vs Dispose(bool) (10)
Estoy confundido acerca de disponer. Estoy intentando que mi código elimine los recursos correctamente. Así que he estado configurando mis clases como IDisposable (con un método Dispose) asegurándome de que se llama al método Dispose.
Pero ahora FXCop me está diciendo muchas cosas sobre Disposing = false y llamando a Dispose (false).
No veo un método de eliminación que tenga un bool. ¿Necesito hacer uno? Si es así, ¿por qué? ¿Por qué no simplemente tener un método que se llama cuando está desechando?
Vi un código aquí: http://msdn.microsoft.com/en-us/library/ms244737.aspx que muestra cómo hacer un método de eliminación que toma un bool. Dice que es para recursos nativos vs administrados. Pero pensé que todo el punto de disposición era solo para recursos no administrados.
Además, la línea de la que se queja FXCop es esta:
~OwnerDrawnPanel()
{
_font.Dispose();
}
Dice:
CA1063: Microsoft.Design: Modifique ''OwnerDrawnPanel. ~ OwnerDrawnPanel ()'' para que llame a Dispose (false) y luego vuelva.
Pero Font no tiene un Dispose (bool) en él (que yo pueda encontrar).
En resumen:
¿Por qué necesito un Dispose (bool)? y si lo hago, ¿por qué Font no lo tiene? y como no lo tiene, ¿por qué FXCop me pide que lo use?
Gracias por todas las excelentes respuestas. Creo que lo entiendo ahora. Aquí está
La respuesta tal como la veo:
La eliminación de los recursos "no administrados" se divide en dos categorías:
- Los recursos que se envuelven en una clase administrada (es decir, mapa de bits, fuente, etc.), pero aún deben descartar que se los llame para limpiarlos correctamente.
- Recursos que ha asignado, que son representaciones de recursos nativos (es decir, contextos de dispositivo que deben ser liberados)
Dispose (bool) se usa para diferenciar los dos:
- Cuando Dispose se llama directamente a su objeto, desea liberar ambos tipos de recursos "no administrados".
- Cuando su objeto está listo para la recolección de basura, no necesita preocuparse por el primer tipo de recursos. El recolector de basura se ocupará de ellos cuando los limpie. Solo debe preocuparse por los verdaderos recursos nativos que haya asignado (si corresponde).
Al estar de acuerdo con Kumar, el patrón Dispose(bool disposing)
también está documentado en MSDN . La distinción no es entre recursos administrados y no administrados, sino si el código o el tiempo de ejecución llaman a Dispose
.
Casi nunca debería necesitar usar finalizadores. Son solo para clases que contienen directamente recursos no administrados, y en .NET 2.0+, estos deben estar empaquetados en SafeHandle.
Creo que Dispose(true)
liberará los recursos administrados y no administrados, ya que no necesitamos volver a llamar, por eso escribimos GC.SupressFinalize()
después de Dispose(true)
.
Llamamos a Dispose(false)
en los destructores para liberar recursos no administrados y será invocado por Runtime y no por el código del usuario.
El patrón de implementación de un public void Dispose()
público public void Dispose()
, protected virtual void Dispose(bool)
y ~ClassName()
finalizers es una práctica recomendable recomendada por Microsoft como una forma de organizar ordenadamente su código de limpieza para recursos administrados y no administrados.
Básicamente, el código que usa su clase Disposable
debería llamar a Dispose()
, pero si no lo hace, el finalizador ~ClassName()
será llamado por Garbage Collection, y según el que se use, usted configurará el argumento para Dispose(bool)
como verdadero o falso, y en su Dispose(bool)
, solo limpia los recursos gestionados si el argumento es verdadero.
La advertencia que está recibiendo parece recomendar específicamente que use esta práctica en su método de finalización ~ClassName()
.
Encontré un buen artículo sobre la implementación correcta de la interfaz IDispose: http://msdn.microsoft.com/en-us/library/ms244737(v=vs.80).aspx
FxCop dice que debes implementar el patrón Desechable como se describe here . Tenga en cuenta que no debe usar finalizadores para deshacerse de recursos administrados como _font
is. Los finalizadores se usan para limpiar recursos no administrados . Si no ejecuta la lógica de limpieza en el método Dispose de su (sub) clase, el recolector de basura la ejecuta de manera no determinista .
También tenga en cuenta que es muy raro que necesite hacer algo en el destructor. Regularmente, todo está a cargo del recolector de basura. Por ejemplo, en su código, no necesita disponer el objeto _font
en el OwnerDrawnPanel
. Como el panel está siendo limpiado por el GC, también lo será, porque el panel fue el único que hizo referencia a él, ¿no?
En general, si posee objetos desechables, solo tiene que desecharlos cuando se llame a su propio método de eliminación. Pero NO en el destructor. Cuando su destructor se está ejecutando, puede apostar que también se están limpiando todos sus objetos agregados.
Dispose(bool)
es un patrón para implementar Finalize
y Dispose
para limpiar los recursos no administrados, vea esto para obtener detalles
Dispose(bool)
no está destinado a ser público y es por eso que no lo ve en Font
.
En caso de que algún usuario de su clase olvide llamar a Dispose en su método, liberará los recursos no administrados solo haciendo una llamada a Dispose(false)
en el Finalizer
.
En caso de que IDispose se invoque correctamente, se llama a Dispose en los recursos administrados y también se ocupa de los no administrados.
La bandera es para distinguir los dos casos.
Es un patrón recomendado por MSDN.
IDisposable
proporciona un método con la firma
public void Dispose()
Las mejores prácticas de Microsoft ( msdn.microsoft.com/en-us/library/fs2xkftw.aspx ) recomiendan hacer un segundo método privado con la firma
private void Dispose(bool)
Su método de eliminación pública y el Finalizador deben llamar a este método de eliminación privada para evitar deshacerse de los recursos administrados varias veces.
Puede corregir la advertencia que está recibiendo al implementar IDisposable y deshacerse de su objeto de fuente en el método de eliminación, o al crear un método de eliminación Dispose(bool)
en su clase, y hacer que el finalizador llame a ese método.