tags:

views:

154

answers:

6

Consider the following code:

namespace DisposeTest
{
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Calling Test");

            Test();

            Console.WriteLine("Call to Test done");
        }

        static void Test()
        {
            DisposeImplementation di = new DisposeImplementation();
        }
    }

    internal class DisposeImplementation : IDisposable
    {
        ~DisposeImplementation()
        {
            Console.WriteLine("~ in DisposeImplementation instance called");
        }
        public void Dispose()
        {
            Console.WriteLine("Dispose in DisposeImplementation instance called");
        }
    }
}

The Dispose just never get's called, even if I put a wait loop after the Test(); invocation. So that quite sucks. I want to write a class that is straightforward and very easy to use, to make sure that every possible resource is cleaned up. I don't want to put that responsibilty to the user of my class.

Possible solution: use using, or call Dispose myself(basicly the same). Can I force the user to use a using? Or can I force the dispose to be called?

Calling GC.Collect(); after Test(); doesn't work either.

Putting di to null doesn't invoke Dispose either. The Deconstructor DOES work, so the object get's deconstructed when it exits Test()

Ok guys, it's clear now!

Thank you all for your answers! I will add a warning in the comment!

+1  A: 

You're supposed to dispose of it yourself, either calling the Dispose method or using using. Remember, it's not a deconstructor!

If you can't trust the users of your class to dispose of resources properly, they will probably mess up in other ways anyway.

ho1
+2  A: 

Dispose does not get called automatically. You need to use a using clause or call it manually.

See http://msdn.microsoft.com/en-us/library/aa664736%28VS.71%29.aspx

And just to preempt another idea you might have: you cannot call dispose from the destructor... I tried this some time ago in a project.

Rodrick Chapman
There's no such thing as a destructor in C#. They're called finalizers. You can actually call it from the finalizer (see my answer), but there may be special precautions you need to make.
Thorarin
C# does indeed have destructors: see the language spec or http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
Rodrick Chapman
+1  A: 

You will have to call Dispose explicitly or by wrapping the object in a using statement. Example:

using (var di = new DisposeImplementation())
{
}

Possible solution: use using, or call Dispose myself(basicly the same).

Using using is the same as calling Dispose inside a finally block.

Anne Sharp
+2  A: 

All the answers are (more or less) correct, here's an example:

static void Test()
{
    using (DisposeImplementation di = new DisposeImplementation())
    {
        // Do stuff with di
    }
}

Manually calling Dispose will also work, but the advantage of the using statement is that the object will also be disposed when you leave the control block because an exception is thrown.

You could add a finalizer that handles the resource disposing in case someone "forgets" to use the IDisposable interface:

public class DisposeImplementation : IDisposable
{    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    }

    ~DisposeImplementation()
    {
        Dispose(false);
    }
}

See this question for additional information. However, this is just compensating for people not using your class correctly :) I suggest you add a big fat Debug.Fail() call to the Finalizer, to warn the developer of their mistake.

If you choose to implement the pattern, you'll see that GC.Collect() will trigger disposal.

Thorarin
Any particular reason for the downvote?
Thorarin
+3  A: 

Use this as a pattern/template for your classes

public class MyClass : IDisposable
{
private bool disposed = false;

// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
    Dispose(true);
    // This object will be cleaned up by the Dispose method.
    // Therefore, you should call GC.SupressFinalize to
    // take this object off the finalization queue
    // and prevent finalization code for this object
    // from executing a second time.
    GC.SuppressFinalize(this);
}

// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
    // Check to see if Dispose has already been called.
    if (!this.disposed)
    {
        // If disposing equals true, dispose all managed
        // and unmanaged resources.
        if (disposing)
        {
            // Dispose managed resources.                
            ......
        }

        // Call the appropriate methods to clean up
        // unmanaged resources here.
        // If disposing is false,
        // only the following code is executed.
        ...........................

        // Note disposing has been done.
        disposed = true;

    }
}

// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyClass()
{
    // Do not re-create Dispose clean-up code here.
    // Calling Dispose(false) is optimal in terms of
    // readability and maintainability.
    Dispose(false);
}

}

And of course as mentioned by others don't forget about using(...){} block.

Incognito
+5  A: 

I want to write a class that is straightforward and very easy to use, to make sure that every possible resource is cleaned up. I don't want to put that responsibilty to the user of my class.

You can't do that. The memory management is simply not built to accomodate clueless developers.

The IDisposable pattern is intended for developers as a way of telling an object when they are done with it, instead of having the memory management trying to figure that out by using things like reference counting.

You can use the Finalizer as a fallback for users who fail to dispose objects properly, but it doesn't work well as the primary method for cleaning up objects. To work smoothly objects should be disposed properly, so that the more costly Finalizer doesn't ever need to be called.

Guffa
But take care not to call into any other objects in your finalizer. The order of finalization is undefined (especially with circular and other cross-dependencies being allowed), so the only thing a finalizer is allowed to do is clean up unmanaged resources.
Cygon