The Reason
The Reason

Reputation: 7973

Dispose, Finalize, SuppressFinalize methods

Can i implement this two methods in the same class?

public class MyClass : IDisposable
{
  // some implementation
  // if i missed to call Dispose() method;
  ~MyClass()
  {
  // it means, clear all does not mananage resources 
  // but dont use Dispose() method 
  }
  public void Dispose()
  {
   // clear resources
   // if i call this method will i can do this:
   GC.SuppressFinalize()
   // it means dont use Finalizw method for this object
  }
}

Am i right? Because i cant understand this GC.SuppressFinalize() method?

Upvotes: 3

Views: 1142

Answers (1)

Jcl
Jcl

Reputation: 28272

Yes, you can implement both methods as you see.

Generally, the correct pattern if an object can have both managed and unmanaged references is:

public class MyClass : IDisposable
{
  ~MyClass()
  {
    Dispose(false);
  }
  public void Dispose()
  {
    GC.SuppressFinalize(this); 
    Dispose(true);
  }
  public virtual void Dispose(bool disposing)
  {
    if(disposing)
    {
      // clear MANAGED references
    }
    // free UNMANAGED resources
  }
}

But you can implement this as you want. This is just a pattern. For example, if you don't have any unmanaged resources and your class is sealed (so you can be sure it won't use any unmanaged resources, ever), you could implement it just like:

public sealed class MyClass : IDisposable
{
  public void Dispose()
  {
    // release managed references
  }
}

And forget about finalizers.

In the first pattern, what GC.SuppresFinalize(this) is doing, is telling the garbage collector that it should not call the finalizer (the ~MyClass() method) upon freeing the object: if you have specifically called Dispose() then you have already called your virtual Dispose(bool) function, so why call it again?

The problem is that the finalizer by itself in C# is non-deterministic: you don't know when it will be called... you don't even have the guarantee that it'll even be called (although it will during normal cleanup if it was not called before), that's why IDisposable exists, it's a way of deterministically release the managed references held up your objects, and free and release the unmanaged resources allocated by it.

If an object is being freed up by the GC, all managed references that it holds will be released too, so there's no need to clear managed references when a finalizer is called.

However your application should do a best effort to free and release any unmanaged resources it has.

If you forgot to Dispose(), there should be a last chance for them to get freed (when the GC collects the object, or upon the final cleanup when the application runs). That's wehy in the normal pattern you also implement a finalizer, and tell it to clean up unmanaged resources if you have not done it before

Take note that, contrary to popular belief, a call to Dispose() is nothing special, it's just a method call: you could call it FreeMyObject() or FooBar() if you wanted. It does NOT make the garbage collector free up any memory. There's a pattern by using IDisposable, so important that it gets its own language syntax construct (the using block), but it's just that, a pattern. You could do the same thing that Dispose() does without implementing IDisposable at all.

Upvotes: 7

Related Questions