Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two questions about Dispose() and destructors in C#

I have a question about how to use Dispose() and destructors. Reading some articles and the MSDN documentation, this seems to be the recommended way of implementing Dispose() and destructors.

But I have two questions about this implementation, that you can read below:

class Testing : IDisposable
{
    bool _disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed) // only dispose once!
        {
            if (disposing)
            {
                // Not in destructor, OK to reference other objects
            }
            // perform cleanup for this object
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);

        // tell the GC not to finalize
        GC.SuppressFinalize(this);
    }

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

GC.SupressFinalize(this) on Dispose()

When the programmer uses using or calls Dispose() explicity, our class is calling to GC.SupressFinalize(this). My question here is:

  • What this exactly means? Will the object be collected but without calling the destructor?. I guess that the anwswer is yes since destructors are converted by the framework to a Finalize() call, but I'm not sure.

Finalizing without a Dispose() call

Suppose that the GC is going to clean our object but the programmer did not call Dispose()

  • Why don't we dispose resource at this point? In other words, why can't we free resources on destructor?
  • What code must be executed in the if inside, and what outside?

    if (!_disposed) // only dispose once!
    {
       if (disposing)
       {
           //What should I do here and why?
       }
       // And what here and why?
    }
    

Thanks in advance

like image 457
Daniel Peñalba Avatar asked Jan 06 '11 13:01

Daniel Peñalba


People also ask

Why we need to implement Dispose method while we have destructor?

It is always recommended to use Dispose method to clean unmanaged resources. You should not implement the Finalize method until it is extremely necessary. At runtime C#, C++ destructors are automatically converted to Finalize method.

Does Dispose () work like destructor?

Destructor implicitly calls the Finalize method, they are technically the same. Dispose is available with objects that implement the IDisposable interface. The destructor implicitly calls Finalize on the base class of the object.

When the Dispose method is called?

The Dispose() methodThe Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.

Is finalize a destructor or method?

Finalizers (historically referred to as destructors) are used to perform any necessary final clean-up when a class instance is being collected by the garbage collector. In most cases, you can avoid writing a finalizer by using the System. Runtime.


2 Answers

1. What does SuppressFinalize do?

It unregisters the object from the finalizer list, ie when the GC later collects the object it will ignore the presence of the destructor. This is a big gain in performance since the destructor would otherwise require the object's collection, and that of everything it references, to be delayed.

2. Why don't we dispose [managed] resource at this point? In other words, why can't we free [managed] resources on destructor?

You could, but it is certain to be pointless: the object you're in has become unreachable so all those owned managed resources are unreachable too. They will be Finalized and collected by the GC in the same run and calling Dispose() on them is unnecessary but not totally without risk or cost.

2a What code must be executed in the if inside, and what outside?

Inside the if(disposing), call _myField.Dispose()

In other words, Dispose of managed resources (objects with a Dispose)

Outside, call code to cleanup (close) unmanaged resources, like Win32API.Close(_myHandle).

Note that when you don't have unmanaged resources, as will usually be the case (look up SafeHandle), you don't need a destructor and therefore no SuppressFinalize.

And that makes that the complete (official) implementation of this pattern is only needed because of the possibility that Test is inherited from.
Note that the Dispose(bool) is protected. When you declare your class Testing to be sealed, it is totally safe and conforming to omit the ~Testing().

like image 68
Henk Holterman Avatar answered Oct 04 '22 15:10

Henk Holterman


First part:

When GC.SupressFinalize(this) is called, GC is informed that the object has already freed its resources and it can be garbage-collected as any other object. And yes, finalization and "destructors" are the same thing in .NET.

Second part:

Finalization is done by a separate thread and we have no control on time and order of finalization, so we don't know whether any other objects are still available or are already finalized. For this reason, you can't reference other object outside the disposing block.

like image 32
NOtherDev Avatar answered Oct 04 '22 16:10

NOtherDev