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 Busa un Driver, le Drivera deux Shoes, chacun Shoea un Shoelace. Tout cela est très idiot.
Ajouter un objet IDisposable à Shoelace
Plus tard, je décide qu'une opération sur le Shoelacepourrait être multi-thread, donc j'ajoute un EventWaitHandlepour les threads avec lesquels communiquer. Alors Shoelacemaintenant 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 IDisposablesur Shoelaceet 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 Shoelacelui-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 Shoecrée un Shoelace, donc Shoedoit l'être IDisposableaussi.
Et Drivercrée Shoeainsi Driverdoit être IDisposable. Et Buscrée Driverainsi Busdoit être IDisposableet ainsi de suite.
Soudain, mon petit changement Shoelaceme cause beaucoup de travail et mon patron se demande pourquoi je dois payer Buspour 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?