Search code examples
c#dispose

still trying to understand the dispose pattern


i've read msdn and various posts about dispose pattern, and there are still a couple of things i don't understand. I've written the following code to test the dispose pattern. Please note that there aren't unmanged resources, i'm using vs2008 and .net 3.5 :

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void tryDispose()
    {
        //test 1 : allocate resource and leave manage it to gc
        BL.myclass df = new BL.myclass();
        //test 2 : try to force garbage collecting
        //GC.Collect();
       //test 3 : call dispose myself
       //using (BL.myclass df = new BL.myclass())
        //{ 

        //}

    }

    private void button1_Click(object sender, EventArgs e)
    {
        tryDispose();
    }

this is my disposable class:

class myclass: IDisposable
{

    private StronglyTypedDs myDS;
    private bool _disposed;

    public myclass()
    {
        using (myDSTableAdapter docDocadpt = new myDSTableAdapter())
        {
            myDS = new StronglyTypedDs();
            docDocadpt.Fill(myDS.TheTable);
        }
    }


    #region IDisposable Members

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

    ~myclass()
    {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                if (myDS != null)
                    myDS .Dispose();
                myDS = null;
            }
        }
        _disposed = true;
    }


    #endregion

}

The results are :

test 1a - just instantiating myclass, the destructor is commentend since myclass doesn't contains unmanaged resources : myclass.dispose is not called, even if i close the application (whose dispose is executed instead) . So what's the state of the dataset once i close the application ?

test 1b - uncommenting destructor, it's ok all disposes are called when i close the application.

test 2a and 2b - i do the above test just calling gc.collect : the behaviour is identical to test 1a and 1b respectively

test 3 - everything works fine (of course)

many posts says that, if myclass doesn't contains unmanaged resources, i don't need to add the destructor; yet in my tests , if i don't add the destructor , myclass.dispose doesn't get called when i close the application. I haven't waited for the gc to run by itself (if i remember correctly gc.collect doesn't guarantes the class instance is deallocated) to check if it will call myclass.dispose . So what's the correct implemention : always define e destructor or avoid it if myclass contains only managed resources ? If i had filled all generations levels, would had the gc called myclass dispose or not without having implemented a destructor?

Finally i've noticed that if i define a destructor , but don't declare the class as implementing IDisposable, the disposing chain works anyway. This could make sense since the destructor might be translated to finalize in IL. But i find it really confusing : is it some kind of "implicit" interface implementation i don't know? gc can dispose the item but users can't

thank you in advance

Stefano


Solution

  • Trust your Garbage Collector. Managed resources will get cleaned up, eventually. There is no need for a finalizer or implementing IDisposable unless you have some external resource that needs to be released.

    This typically means that you only should implement IDisposable when you either:

    1. Are wrapping a native resource. (In this case, you probably also want a finalizer.)
    2. Are encapsulating a class which implements IDisposable. (In this case, you want IDisposable, but don't need to implement a finalizer/destructor.)

    Part of the confusion with IDisposable, in my opinion, is that it covers quite a few use cases, and the proper implementation changes depending on what you're doing (ie: wrapping native resources, wrapping other IDisposable classes, or using Factored types). To address this, I've written a multiple part series on IDisposable - it might help clarify some of this for you.