tags:

views:

125

answers:

4

I have few Question for which I am not able to get a proper answer .

1) Why should we call SuppressFinalize in the Dispose function when we dont have a destructor .

2) Dispose and finalize are used for freeing resources before the object is garbage collected. Whether it is managed or unmanaged resource we need to free it , then why we need a condition inside the dispose funtion , saying pass 'true' when we call this overriden function from IDisposable:Dispose and pass false when called from a finalize.

See the below code i copied from net.

class Test : IDisposable
   {
     private bool isDisposed = false;

     ~Test()
     {
       Dispose(false);
     }

     protected void Dispose(bool disposing)
     {
       if (disposing)
       {
         // Code to dispose the managed resources of the class
       }
       // Code to dispose the un-managed resources of the class

       isDisposed = true;
     }

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

what if I remove the boolean protected Dispose function and implement the as below.

   class Test : IDisposable
   {
     private bool isDisposed = false;

     ~Test()
     {
       Dispose();
     }


     public void Dispose()
     {
      // Code to dispose the managed resources of the class
      // Code to dispose the un-managed resources of the class
      isDisposed = true;

      // Call this since we have a destructor . what if , if we dont have one 
       GC.SuppressFinalize(this);
     }
   }       
+2  A: 

Keep the first version, it is safer and is the correct implementation of the dispose pattern.

  1. Calling SuppressFinalize tells the GC that you have done all the destruction/disposing yourself (of resources held by your class) and that it does not need to call the destructor.

  2. You need the test in case the code using your class has already called dispose and you shouldn't tell the GC to dispose again.

See this MSDN document (Dispose methods should call SuppressFinalize).

Oded
Yes I do understand the that SupressFinalze will prevent the GC from calling Finalize . But my doubt is when I am not having a destuctor why we need to call SupressFinalze . Because Finalize will be ony called for those objets in the finalzer queue and my object dont have destructor so any way GC is not going to call .2) My second pint is , why dispose pattens insist about an overloaded dispose funtion which takes a boolean . which will control the release of managed or unmanaged resources .when the object is going to be disposed , why we need to treat resource seperatly , lets free all.
somaraj
That rule is only relevant when you need a finalizer or you need to allow subclasses to have a finalizer. In many situations this isn't the case.
Jon Skeet
@somaraj: The point is that *your* class may not have a finalizer, but a *subclass* might.
Jon Skeet
@JonSkeet: Why would you want to supress a subclass' finalizer? base.Dispose() is called from the subclass Dispose() so there should already be a GC.SupressFinalize there.
adrianm
@adrianm: You would want to suppress finalization if you've been disposed, on the reasonable assumption that all the clean-up required will have taken place. `GC.SuppressFinalize()` is normally in the *parameterless* Dispose method, rather than the one with the "disposing" parameter which is virtual - in the standard (long) pattern.
Jon Skeet
+2  A: 

I'm going out on a limb here, but... most people don't need the full-blown dispose pattern. It's designed to be solid in the face of having direct access to unmanaged resources (usually via IntPtr) and in the face of inheritance. Most of the time, neither of these is actually required.

If you're just holding a reference to something else which implements IDisposable, you almost certainly don't need a finalizer - whatever holds the resource directly is responsible for dealing with that. You can make do with something like this:

public sealed class Foo : IDisposable
{
    private bool disposed;
    private FileStream stream;

    // Other code

    public void Dispose()
    {
        if (disposed)
        {
            return;
        }
        stream.Dispose();
        disposed = true;
    }
}

Note that this isn't thread-safe, but that probably won't be a problem.

By not having to worry about the possibility of subclasses holding resources directly, you don't need to suppress the finalizer (because there isn't one) - and you don't need to provide a way of subclasses customising the disposal either. Life is simpler without inheritance.

If you do need to allow uncontrolled inheritance (i.e. you're not willing to bet that subclasses will have very particular needs) then you need to go for the full pattern.

Note that with SafeHandle from .NET 2.0, it's even rarer that you need your own finalizer than it was in .NET 1.1.


To address your point about why there's a disposing flag in the first place: if you're running within a finalizer, other objects you refer to may already have been finalized. You should let them clean up themselves, and you should only clean up the resources you directly own.

Jon Skeet
Hi Jon, just nitpicking, but the sentence "whatever holds the resource directly can deal with that", should probably be "will deal with that", (ie. "can" --> "will") to emphasize the point that it's not the outer class' job to handle it at all.
Lasse V. Karlsen
@Lasse: Nitpick away :) Will edit.
Jon Skeet
@Jon Skeet ,One more Question, Since System.Object is the base of all the objects ,which by default has a finalize method implemented , even though we have not provided a destructor , wont GC put this in the finalize queue ? or why do we say that if we dont provide a destrutor object wont be put in the finalize queue ? Because by virtue of inheritance protected members are like private members of derived class .
somaraj
A: 

Thanks to every one , though i had bit and pieces of information i was not able to get a complete idea of dispose pattern .When read MSDN "Implementing a Dispose Method" in the light of your answers i got a complete idea . My biggest doubt was why we provide a seperate virtual version of the Dispose (bool) . what I understood is its a template pattern which ensure that the derived calls dispose is called when an object of base type containing derived object is garbage collected .

One more Question remains .

Since all the System.Object is the base of all the objects ,which by default has a finalize method implemented , even though we have not provided a destructor , wont GC put this in the finalize queue ? or why do we say that if we dont provide a destrutor object wont be put in the finalize queue ? Because by virtue of inheritance protected members are like private members of derived class .

somaraj
A: 

Here are the main facts

1) Object.Finalize is what your class overrides when it has a Finalizer. the ~TypeName() destructor method is just shorthand for 'override Finalize()' etc

2) You call GC.SuppressFinalize if you are disposing of resources in your Dispose method before finalization (i.e. when coming out of a using block etc). If you do not have a Finalizer, then you do not need to do this. If you have a Finalizer, this ensures that the object is taken off of the Finalization queue (so we dont dispose of stuff twice as the Finalizer usually calls the Dispose method as well)

3) You implement a Finalizer as a 'fail safe' mechanism. Finalizers are guaranteed to run (as long as the CLR isnt aborted), so they allow you to make sure code gets cleaned up in the event that the Dispose method was not called (maybe the programmer forgot to create the instance within a 'using' block etc.

4) Finalizers are expensive as Types that have finalizers cant be garbage collected in a Generation-0 collection (the most efficient), and are promoted to Generation-1 with a reference to them on the F-Reachable queue, so that they represent a GC root. it's not until the GC performs a Generation-1 collection that the finalizer gets called, and the resources are released - so implement finalizers only when very important - and make sure that objects that require Finalization are as small as possible - because all objects that can be reached by your finalizable object will be promoted to Generation-1 also.

Dean Chalk