10

I'm working on a piece of library code around IDisposable. The managed path (via using) is easily testable. I'm wondering about the finalizer though: Is calling System.GC.Collect() sufficient to force the finalizer to run?

David Schmitt
  • 58,259
  • 26
  • 121
  • 165
  • If you stick to the prescribed pattern for IDisposable, I'm sure that unit testing it is going to be that useful. – Mitch Wheat Oct 29 '08 at 10:49
  • sorry, that should have been "I'm not sure that unit testing it is going to be that useful... – Mitch Wheat Oct 29 '08 at 10:58
  • @Mitch: implementing IDisposable correctly, so that managed and unmanaged resources are disposed of at the right moment is not trivial. As the library code in question is responsible for exactly that I don't see a point in _not_ testing that ... – David Schmitt Oct 29 '08 at 11:01
  • http://stackoverflow.com/a/17014062/339384 – constructor Apr 27 '15 at 11:17

4 Answers4

8

No, the GC.Collect() call is asynchronous, you would also need to call this:

System.GC.WaitForPendingFinalizers();
RickL
  • 2,811
  • 3
  • 22
  • 35
  • 1
    I think the GC.Collect() itself is synchronous (i.e. it will have freed any memory it can by the time it returns) but the finalizers themselves run separately. I could be entirely wrong though... – Jon Skeet Oct 29 '08 at 11:06
  • I'm doing both now and the test passed every time. That is, called the correct extension point from the finalizer. – David Schmitt Oct 29 '08 at 21:53
  • Note to self: also check that the initialisation code of the class in question doesn't "root" the object somewhere. – David Schmitt Oct 30 '08 at 21:39
  • @EricBurcham: an example where I use that is here: https://github.com/daszat/zetbox/blob/master/Tests/DisposableMockTemplate.cs – David Schmitt Feb 19 '14 at 14:54
  • this doesn't work for me. I called `GC.Collect()` and then `GC.WaitForPendingFinalizers();` and at no point is `disposing` ever `false` – Matthew Jul 24 '19 at 20:32
2

I would take a look at Dispose, Finalization, and Resource Management its the best reference on the subject I know of. Using their pattern:

~ComplexCleanupBase()
{
    Dispose(false);
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

protected override void Dispose(bool disposing)
{
   if (!disposed)
   {
        if (disposing)
        {
            // dispose-only, i.e. non-finalizable logic
        }

        // new shared cleanup logic
        disposed = true;
    }

    base.Dispose(disposing);
}

You wind up with dead simple Finalizer/Dispose() methods and a testable Dispose(bool). No need to force Finalization or anything using the GC class.

Rob McCready
  • 1,909
  • 1
  • 19
  • 20
0

Could you mock out an IDisposable interface and expect a call to Dispose? That would at least let you see when the object is actually disposed.

brien
  • 4,400
  • 4
  • 30
  • 32
  • Setting a breakpoint is sufficient to discover that. I'm testing the Dispose()'s implementation though, not whether it's called. – David Schmitt Jan 24 '09 at 20:12
0

I think I would lean towards making Finalize() call another method, and test that the other method does what you want. You wouldn't get 100% code coverage, but at least you'd know that the method releases the object's resources properly.

Ben Fulton
  • 3,988
  • 3
  • 19
  • 35