Commencez avec ces simples classes...
Disons que j'ai un simple ensemble de classes comme ceci:
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;
}
Un Bus
a Driver
, Driver
deux Shoe
s, chaque Shoe
a Shoelace
. Tous très bête.
Ajouter un IDisposable objet à Lacet
Plus tard, j'ai décider que certaines opérations sur l' Shoelace
pourraient être multi-thread, j'ai donc ajouter un EventWaitHandle
pour les filets de communiquer avec. Donc, Shoelace
ressemble maintenant à ceci:
class Shoelace
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
// ... other stuff ..
}
Mettre en œuvre IDisposable sur Lacet
Buit maintenant FxCop va se plaindre: "mettre en Œuvre IDisposable sur "Lacet" parce qu'il crée des membres de la suite de IDisposable types: 'EventWaitHandle'."
Okay, je vais mettre en oeuvre IDisposable
sur Shoelace
et ma jolie petite classe devient cette horrible gâchis:
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;
}
}
Ou (comme l'a souligné par les commentateurs) depuis Shoelace
lui-même n'a pas de ressources non managées, je pourrais utiliser la plus simple de disposer de la mise en œuvre sans avoir besoin de l' Dispose(bool)
et Destructeur:
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);
}
}
Regarde avec horreur que IDisposable se propage
Droit qui est fixe. Mais maintenant, FxCop va se plaindre qu' Shoe
crée un Shoelace
, alors Shoe
doit IDisposable
trop.
Et Driver
crée Shoe
donc Driver
doit IDisposable
.
et Bus
crée Driver
donc Bus
doit IDisposable
et ainsi de suite.
Tout à coup, mon petit changement d' Shoelace
est à l'origine de beaucoup de travail et mon patron est de se demander pourquoi j'ai besoin de checkout Bus
de faire un changement d' Shoelace
.
La Question
Comment voulez-vous empêcher cette propagation de l' IDisposable
, mais encore de s'assurer que vos objets managés sont correctement éliminés?