Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do you prevent IDisposable from spreading to all your classes?
    primarykey
    data
    text
    <h2>Start with these simple classes...</h2> <p>Let's say I have a simple set of classes like this: </p> <pre><code>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; } </code></pre> <p>A <code>Bus</code> has a <code>Driver</code>, the <code>Driver</code> has two <code>Shoe</code>s, each <code>Shoe</code> has a <code>Shoelace</code>. All very silly. </p> <h2>Add an IDisposable object to Shoelace</h2> <p>Later I decide that some operation on the <code>Shoelace</code> could be multi-threaded, so I add an <code>EventWaitHandle</code> for the threads to communicate with. So <code>Shoelace</code> now looks like this:</p> <pre><code>class Shoelace { private AutoResetEvent waitHandle = new AutoResetEvent(false); bool tied = false; // ... other stuff .. } </code></pre> <h2>Implement IDisposable on Shoelace</h2> <p>But now <a href="https://en.wikipedia.org/wiki/FxCop" rel="noreferrer">Microsoft's FxCop</a> will complain: <em>"Implement IDisposable on 'Shoelace' because it creates members of the following IDisposable types: 'EventWaitHandle'."</em></p> <p>Okay, I implement <code>IDisposable</code> on <code>Shoelace</code> and my neat little class becomes this horrible mess:</p> <pre><code>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; } } </code></pre> <p>Or (as pointed out by commenters) since <code>Shoelace</code> itself has no unmanaged resources, I might use the simpler dispose implementation without needing the <code>Dispose(bool)</code> and Destructor:</p> <pre><code>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); } } </code></pre> <h2>Watch in horror as IDisposable spreads</h2> <p>Right that's that fixed. But now FxCop will complain that <code>Shoe</code> creates a <code>Shoelace</code>, so <code>Shoe</code> must be <code>IDisposable</code> too. </p> <p>And <code>Driver</code> creates <code>Shoe</code> so <code>Driver</code> must be <code>IDisposable</code>. And <code>Bus</code> creates <code>Driver</code> so <code>Bus</code> must be <code>IDisposable</code> and so on.</p> <p>Suddenly my small change to <code>Shoelace</code> is causing me a lot of work and my boss is wondering why I need to checkout <code>Bus</code> to make a change to <code>Shoelace</code>.</p> <h2>The Question</h2> <p>How do you prevent this spread of <code>IDisposable</code>, but still ensure that your unmanaged objects are properly disposed?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload