implementar c# .net memory-management idempotent

c# - implementar - ¿Deben ser idempotentes las implementaciones IDisposable.Dispose()?



dispose() c# (4)

El marco Microsoft.NET proporciona la interfaz IDisposable que requiere una implementación del método void Dispose() . Su propósito es permitir la liberación manual o basada en el alcance de recursos costosos que una implementación IDisposable puede haber asignado. Los ejemplos incluyen colecciones de bases de datos, flujos y manejadores.

Mi pregunta es, si la implementación del método Dispose() es idempotente: cuando se llama más de una vez en la misma instancia, la instancia debe ''desecharse'' solo una vez, y las llamadas subsiguientes no para lanzar excepciones. En Java, la mayoría de los objetos que tienen un comportamiento similar (nuevamente, las secuencias y las conexiones de base de datos vienen a mi mente como ejemplos) son idempotentes para su operación close() , que es el análogo del método Dispose() .

Sin embargo, mi experiencia personal con .NET (y con Windows Forms en particular), muestra que no todas las implementaciones (que son parte del propio marco .NET ) son idempotentes, por lo que las llamadas subsiguientes a estos lanzan una ObjectDisposedException . Esto realmente me confunde sobre cómo debería abordarse la implementación de un objeto desechable. ¿Existe una respuesta común para el escenario, o depende del contexto concreto del objeto y su uso?


si la implementación del método Dispose() es idempotente

Sí, debería. No se sabe cuántas veces se llamará.

Desde la implementación de un método de disposición en MSDN:

Un método de desechar debe ser invocable varias veces sin lanzar una excepción.

Un objeto con una buena implementación de IDispose tendrá un indicador de campo booleano que indica si ya se ha eliminado y en las llamadas posteriores no hace nada (ya que ya se eliminó).


Personalmente, sí, siempre hago que Dispose () sea idempotente.

Durante el ciclo de vida habitual de un objeto en una aplicación dada puede no ser necesario: el ciclo de vida desde la creación hasta la eliminación puede ser determinista y bien conocido.

Sin embargo, igualmente, en algunas aplicaciones podría no ser tan claro.

Por ejemplo, en un escenario decorador: puedo tener un objeto desechable A, decorado con otro objeto desechable B. Es posible que desee disponer explícitamente de A, y sin embargo, Desechar en B también puede disponer de la instancia que envuelve (piense: fluye).

Dado que es relativamente fácil hacer que Disose idempotent (es decir, si ya está dispuesto, no hacer nada), parece tonto no hacerlo.


Sí, también asegúrese de que los otros métodos de la clase respondan correctamente cuando se llaman cuando el objeto ya se ha eliminado.

public void SomeMethod() { if(_disposed) { throw new ObjectDisposedException(); } else { // ... } }


Desde MSDN:

Permita que un método Dispose se llame más de una vez sin lanzar una excepción. El método no debe hacer nada después de la primera llamada.