Share via


Resource Releasing with Dispose Pattern

Introduction


In nowadays projects, it is common to find a situation in which we handle with memory resources. There are two kinds of resources, the managed and the unmanaged by the .Net Framework's Virtual Machine, the Common Language Runtime (CLR). We have to release the memory occupied by those objects after we use them. When a managed object is not being used anymore, the garbage collector release the memory allocated to it automatically. Though, it is not possible to know when the garbage collection will happen. The unmanaged resources, like database connections, files and external hardwares, have to be manually released.

How to implement it?


You must implement the IDisposable interface to release the resource correctly so that any client class will not be able to access an already released resource (otherwise, an ObjectDisposedException will be thrown instead). It is recommended to call the Dispose method only where you should clean the resource. On the code below I show the different approaches to release memory resources:

  • Try-finally

The try-finally block is the oldest way to consume resources since the 'using' keyword was implemented on .Net Framework. A basic rule to consume a resource is guarantee success for whom is going to use it. Surely a mistake can happen with this operation, this explains the reason to place the instructions within a try block. We make an explicit call to the Dispose method in the finally block. It is safe because the finally block will always be executed. Then, on this block occurs the resource releasing.

/// <summary>
/// Creates a new file in a given directory.If the file already exists,
/// modify its name and try to create it again.
/// </summary>
public void ExecResource()
 {
     FileStream fs = null;
     string path = @"C:\Users\Thiago\Dropbox\Teste.txt";
     try
     {
         fs = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite);
     }
     catch (IOException)
     {
         if (File.Exists(path))
         {
             var newPath = path.Replace("Teste", "outro");
             //try to create the file with a new path
             fs = new FileStream(newPath, FileMode.CreateNew, FileAccess.ReadWrite);
         }
     }
     finally
     {
         if (fs != null)
            fs.Dispose();
     }
 }
  • using

The difference of this approach is by the fact that this block make an implicit call to the Dispose method at the end of its scope. It is necessary for the class that uses the using block to implement the IDisposable interface. It is recommended, as a language feature, because avoids a manual cleaning. The compiler generates the try-finally blocks. You instantiate the resource within the using statement:

/// <summary>
 /// Loads a text file and copy it to a new file.
 /// </summary>
 /// <param name="path"></param>
 public void ExecResource(string path)
 {
     string destPath = @"C:\Users\Thiago\Dropbox\Teste2.txt";

     using (TextReader txt = new StreamReader(path))
     {
         if (File.Exists(path))
         {
             File.Copy(path, destPath);
             Console.WriteLine("File copied successfully.");
         }
     }
 }

Note: Most of .Net Framework classes, such as StreamReader / StreamWriter, DataTable, among others, already implements the Dispose method by IDisposable. In this case, therefore, you should stick only to the use of the using block.

  • Finalizers

Finalizers are methods called at the end of the Garbage Collector scan cycle. They perform the unmanaged resources cleanup as well. It is an alternative used when the object that consumes the resource does not call the Dispose method. Note that it is not necessary to implement a finalizer if you have already called Dispose() in your finally block or if you have used a using block implementing IDisposable. For instance, take a look at the BinaryWriter class. Some authors such as Jeffrey Richter (CLR via C#, 2010) like to implement a finalizer along with the Dispose method to have more control over the resource life cycle.

Implementing the Dispose Pattern


  1. First, create a class that will implement the IDisposable interface;

  2. Create a flag that will keep track whether the resource has been released or not (bool disposed);

  3. Create a Dispose method that is going to receive a boolean disposing parameter that, depending on the value, if it is true it will release the managed resources and false, the unmanaged. This method has to be declared as protected virtual due to inheritance hierarchy. If you want to define derived classes that will need to release unmanaged resources after use, in the subclass you must override it. Note: the base class (if any) should not have any finalizer.

4) Create a parameterless Dispose method. It will call the Dispose(true) method that in fact will perform the managed resources release operations and will make a call to the GC's SuppressFinalize method, preventing it to call the finalizer to this object. 

  1. Use the finalizer only if you have not implemented your code within a try-finally block with a Dispose call.
class ResourceExample : IDisposable
{
    bool disposed = false;

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
          return;

        if (disposing)
        {
          //release managed resources by CLR
        }

        //else: release unmanaged resources by CLR

        disposed = true;
    }

    //if you want to override the finalizer, write 'false' at Dispose(disposing)

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

This topic is long enough, so I advise you read more about Dispose Pattern on the links below.

See Also


 See ya,
Thiago