39
votes

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!

7

7 Answers

58
votes

A couple of important points should be made to address the OP's question:

  1. .NET GC is non-deterministic (i.e. you never know nor should you depend on when it happens)
  2. Dispose is never called by the .NET Framework; you must call it manually - preferably by wrapping its creation in a using() block.
  3. Explicitly setting a disposable object to null without calling Dispose() on it is a bad thing to do. What happens is that you explicitly set the objects "root reference" to null. This effectively means that you cannot call Dispose later AND more importantly, it sends the object to the GC Finalization Queue for Finalization. Causing Finalization by bad programming practice should be avoided at all costs.

Finalizer: Some developers refer to it as a destructor. And in fact it is even called a Destructor in the C# 4.0 Language Spec (section 1.6.7.6) and in previous versions of the current ECMA-334 spec. Fortunately, the 4th Edition (June 2006) correctly defines Finalizers in Section 8.7.9 and attempts to clear up the confusion between the two in Section 17.12. It should be noted that there are important internal differences (no need to go into those gory details here) between what is traditionally known as a destructor and a Destructor/Finalizer in the .NET Framework.

  1. If a Finalizer is present, then it will be called by the .NET Framework if and only if GC.SuppressFinalize() is not called.
  2. You should NEVER explicitly call a finalizer. Fortunately, C# will not explicitly allow this (I don't know about other languages); though it can be forced by calling GC.Collect(2) for the 2nd generation of the GC.

Finalization: Finalization is the .NET Framework's way to deal with the 'graceful' cleanup and releasing of resources.

  1. It only occurs when there are objects in the Finalization Queue.
  2. It only occurs when a garbage collection occurs for Gen2 (which is approx 1 in every 100 collections for a well-written .NET app).
  3. Up to and including .NET 4, there is a single Finalization thread. If this thread becomes blocked for any reason, your app is screwed.
  4. Writing proper and safe finalization code is non-trivial and mistakes can be made quite easily (i.e. accidently allowing exceptions to be thrown from the Finalizer, allowing dependencies on other objects that could already be finalized, etc.)

While this is certainly more info that you asked for, it provides background on how things work and why they work the way they do. Some people will argue that they shouldn't have to worry about managing memory and resources in .NET, but that doesn't change the fact that it needs to be done - and I don't see that going away in the near future.

Unfortunately, the examples above (mistakenly) imply that you need to implement a Finalizer as part of the standard Dispose pattern. However, you should not implement a Finalizer unless you are using UNmanaged code. Otherwise, there are negative performance implications.

I have posted a template for implementing the Dispose pattern here: How do you properly implement the IDisposable pattern?

27
votes

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 resources that are not memory specifically.

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.

15
votes

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.

8
votes

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.

2
votes

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.

2
votes

Dispose does not get called automatically. You need to use a using clause to wrap usage 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.

1
votes

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.