Comience con estas clases simples ...
Digamos que tengo un conjunto simple de clases como esta:
class Bus
{
Driver busDriver = new Driver();
}
class Driver
{
Shoe[] shoes = { new Shoe(), new Shoe() };
}
class Shoe
{
Shoelace lace = new Shoelace();
}
class Shoelace
{
bool tied = false;
}
A Bustiene a Driver, Drivertiene dos Shoes, cada uno Shoetiene a Shoelace. Todo muy tonto.
Agregue un objeto IDisposable a Shoelace
Más tarde decido que alguna operación en el Shoelacepodría ser multiproceso, así que agrego un EventWaitHandlepara que los hilos se comuniquen. Entonces Shoelaceahora se ve así:
class Shoelace
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
// ... other stuff ..
}
Implemento IDisposable en Cordón
Pero ahora FxCop de Microsoft se quejará: "Implemente IDisposable en 'Shoelace' porque crea miembros de los siguientes tipos de IDisposable: 'EventWaitHandle'".
Está bien, puedo aplicar IDisposableen Shoelacey mi clase se convierte en poco aseado este horrible desastre:
class Shoelace : IDisposable
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Shoelace()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
if (waitHandle != null)
{
waitHandle.Close();
waitHandle = null;
}
}
// No unmanaged resources to release otherwise they'd go here.
}
disposed = true;
}
}
O (como lo señalaron los comentaristas) ya que en Shoelacesí mismo no tiene recursos no administrados, podría usar la implementación de disposición más simple sin necesidad de Dispose(bool)Destructor y:
class Shoelace : IDisposable
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
public void Dispose()
{
if (waitHandle != null)
{
waitHandle.Close();
waitHandle = null;
}
GC.SuppressFinalize(this);
}
}
Mire con horror cómo se propaga IDisposable
Correcto, eso es todo arreglado. Pero ahora FxCop se quejará de que Shoecrea un Shoelace, por Shoelo que IDisposabletambién debe ser .
Y Drivercrea Shoeasí Driverdebe ser IDisposable. Y Buscrea Driverasí Busdebe ser IDisposabley así sucesivamente.
De repente, mi pequeño cambio Shoelaceme está causando mucho trabajo y mi jefe se pregunta por qué tengo que pagar Buspara hacer un cambio Shoelace.
La pregunta
¿Cómo evita esta propagación IDisposable, pero se asegura de que sus objetos no gestionados se eliminen correctamente?