Commencez par ces classes simples ...
Disons que j'ai un simple ensemble de classes comme celui-ci:
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 Bus
a un Driver
, le Driver
a deux Shoe
s, chacun Shoe
a un Shoelace
. Tout cela est très idiot.
Ajouter un objet IDisposable à Shoelace
Plus tard, je décide qu'une opération sur le Shoelace
pourrait être multi-thread, donc j'ajoute un EventWaitHandle
pour les threads avec lesquels communiquer. Alors Shoelace
maintenant ressemble à ceci:
class Shoelace
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
// ... other stuff ..
}
Implémenter IDisposable sur Shoelace
Mais maintenant FxCop de Microsoft se plaindra: "Implémentez IDisposable sur 'Shoelace' car il crée des membres des types IDisposable suivants: 'EventWaitHandle'."
D' accord, je mets en œuvre IDisposable
sur Shoelace
et ma petite classe propre cette horrible gâchis devient:
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'ont souligné les commentateurs) étant donné que Shoelace
lui-même n'a pas de ressources non gérées, je pourrais utiliser l'implémentation plus simple de dispose sans avoir besoin de Dispose(bool)
et Destructor:
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);
}
}
Regardez avec horreur alors que IDisposable se propage
C'est bien ça fixe. Mais maintenant FxCop se plaindra que Shoe
crée un Shoelace
, donc Shoe
doit l'être IDisposable
aussi.
Et Driver
crée Shoe
ainsi Driver
doit être IDisposable
. Et Bus
crée Driver
ainsi Bus
doit être IDisposable
et ainsi de suite.
Soudain, mon petit changement Shoelace
me cause beaucoup de travail et mon patron se demande pourquoi je dois payer Bus
pour faire un changement Shoelace
.
La question
Comment éviter cette propagation IDisposable
, tout en vous assurant que vos objets non gérés sont correctement éliminés?