Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Please, some clarifications on C# IDisposable

Tags:

c#

I have seen the code below a lot of times in different threads and different forums. This one in particular I picked up from How does GC and IDispose work in C#?.

class MyClass : IDisposable
{
    ...

    ~MyClass()
    { 
        this.Dispose(false);
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        { /* dispose managed stuff also */ }

        /* but dispose unmanaged stuff always */
    }
}

My questions are:

  1. Is it necessary to create an explicit destructor? The class inherits from IDisposable and during GC cleanup Dispose() will be eventually executed.

  2. What is the significance of the parameter 'disposing' in Dispose(bool disposing)? Why is it necessary to differentiate between disposing of managed and unmanaged objects?

like image 859
Ronald Avatar asked Aug 25 '11 08:08

Ronald


2 Answers

The garbage collector itself knows nothing about IDisposable. It will not dispose anything for you - all it will do is call the finalizer.

The point of having the overload with a "disposing" parameter is that the finalizer will call Dispose(false) to indicate that it's been called from the finalizer and managed objects don't need any clean-up, whereas if you call Dispose explicitly (e.g. via a using statement) that will end up calling Dispose(true).

Part of the point of this pattern is that it's extensible for derived classes - only the base class finalizer needs to call Dispose, and everything else will piggy-back on that by overriding Dispose(bool) if necessary.

However, unless you've actually got direct access to unmanaged resources - or expect derived classes to - you probably don't need a finalizer at all. If you do need fairly direct access, then SafeHandle helps to avoid the need to write a finalizer. You should almost never need to write a finalizer these days. Personally I rarely implement IDisposable myself, and when I do it's typically from a sealed class (as I like to seal classes where possible) - and it almost never involves a finalizer... so I just write a single Dispose method to implement the interface and leave it at that. Much simpler.

The full advice for implementing IDisposable in every situation you can imagine is extremely long-winded and complicated. I think it's well worth trying to limit yourself to simpler situations wherever possible.

like image 84
Jon Skeet Avatar answered Nov 09 '22 15:11

Jon Skeet


1 Is it necessary to create an explicit destructor?

Only in the rare case that you are directly owning an unmanaged resource.

The class inherits from IDisposable and during GC cleanup Dispose() will be eventually executed.

The IDisposable interface only enables the use in using(){}blocks. The GC will eventually call Dispose() but that will be (too) late. Note that it will use disposing==false and only try to clean up unmanaged stuff. Which you most likely don't have.

2 What is the significance of the parameter 'disposing' in Dispose(bool disposing)? Why is it necessary to differentiate between disposing of managed and unmanaged objects?

Because there is no need to Dispose() the managed resources when you are Disposing. The algorithm of the GC ensures that your managed resources are already being GC'ed themselves. Calling their Dispose() is at best harmless.

Note that this code is based on the standard implementation pattern. If you leave out the destructor the only reason for the overloaded Dispose(bool) is possible inheritance.

A shorter version, note the sealed :

sealed class MyClass : IDisposable
{
   private FileStream MyManagedResource;

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

       /* dispose managed stuff  */
       if (MyManagedResource != null)
          MyManagedResource.Dispose();  // this is why we do it all
   }

   // ~MyClass() { }

}
like image 25
Henk Holterman Avatar answered Nov 09 '22 14:11

Henk Holterman