.NET IDisposable

Tower

Gawd
Joined
Oct 11, 2001
Messages
840
I've recently had to start writing C# (moving from C++), and one of the first discussions I had today with peers was about IDisposable, as the CLR collects garbage own it's own, the Destructor (or Finalizer) doesn't always get called immediately (as it does in C++).

Here's a quick example of the pattern implemented as I understand it (for reference):

Code:
sealed public class Whatever
{
    private Boolean _disposed;

    public Whatever()
    {
        this._disposed = false;
    }

    ~Destructor()
    {
        Dispose(false);
    }

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

    private void Dispose(bool disposing)
    {
        if (!this._disposed)
        {
            this._disposed = true;

            if (disposing)
            {
                // Free managed resources, object references, etc.
            }

            // Free unmanaged resources, pointers/handles, etc.
        }
    }
}

Why does the IDisposable interface only implement Dispose()? It seems like the pattern emphasizes telling the Garbage Collector to remove this class's destructor (finalizer) from it's queue when called explicitly by Dispose(), and it also encourages having a Disposing(bool disposing) function so that the user can clean up managed/unmanaged resources safely.

Lastly, it keeps track of stupid human tricks with private boolean _disposed, in the event that a user would call Dispose() explicitly on their own, and then leave a try/catch block (or using{} block) and have Dispose() called again.

TL;DR, why doesn't IDisposable force an implementation of:

  • private boolean _disposing
  • Dispose(boolean disposing)
  • Dispose() { Disposing(true); GC.SuppressFinalize(this); }

I expect there's good discussion on this (not always necessary to clean up managed resources, different patterns for locking, etc.) but I'm curious what others with more experience with IDisposable think.
 
Last edited:
My thoughts on the TL;DR series of questions:
1. Interface contracts are for methods/functions, not properties.
2. That method signature is ambiguous. We're under the context of object/resource cleanup, but a contract doesn't determine what to actually do in the implemented interface within your class.
3. An interface contract doesn't dictate usage.

I think much of your question can be boiled down to this:
IDisposable only requires "Dispose()" to be implemented, so why does the recommended implementation have a lot of extra methods and a bit flag tracker?

Much of this implementation involves exposing cleanup for native managed resources, yet also exposing moments to clean up unmanaged resources like COM objects and bare-metal objects. It kinda seems a little hack-ish, but it works well.

Two minor points:
1. There's no need to set "_disposed" to "false" in your constructor; its initial value is "false".
2. A method call has a typo -- Dipose, instead of Dispose.

Edit: Stack Overflow has an over abundance of threads on IDisposable, too.
 
Last edited:
That's a great response, PTNL.

Another question that comes to mind is that IDisposable is so simple, and .NET implements it via try/catch and also via using--so why don't they simply support "Dispose()" as an optional function in a class without requiring inheriting a 6-line class?
 
Another question that comes to mind is that IDisposable is so simple, and .NET implements it via try/catch and also via using--so why don't they simply support "Dispose()" as an optional function in a class without requiring inheriting a 6-line class?
I see part of the reason is so that you get to dictate what goes into a class: properties, methods, inherits, implements, exposure level, etc. There is also some overhead for using try-catch; so if you don't need it for your class, then you're not forced to use it.

Keep in mind that there are some cases where you do not want to use a "using" statement to wrap the scope of a variable. One example involves communications, such as web services and WCF, where a network error can be thrown mid-transit and can never be aborted or rolled back. So in that example, a more typical try-catch-catch-[...]-finally block is better, so that calls are more definitively made, acknowledged, trapped (and aborted), and cleaned up. This MSDN article highlights a potential situation. But the number of situations were you have an object that implements IDisposable -- but would not want to wrap in a "using" statement -- is very limited.
 
Last edited:
That's a great response, PTNL.

Another question that comes to mind is that IDisposable is so simple, and .NET implements it via try/catch and also via using--so why don't they simply support "Dispose()" as an optional function in a class without requiring inheriting a 6-line class?

Most of that is probably compatibility with VB.NET. Rather than just by naming convention, VB has explicit syntax for implementing properties and methods of an interface.

Code:
      Public Class Random 
             : Implements IDisposable

             'Gets called by the end of the using block.
             Public Sub RandomFunctionName(disposing as Boolean) Implements IDisposable.Dispose

If using() just called .Dispose on your object in the Finally block it would actually break VB's implementation of interfaces.
Casting to IDisposable in the Finally block makes it a compile time decision for where the address of that function is, not a pre-compile text replacement.
 
Back
Top