Dispose and Finalizable patterns

For the majority of the objects that your app creates, you can rely on .NET's garbage collector to handle memory management. However, when you create objects that include unmanaged resources, you must explicitly release those resources when you finish using them in your app. The most common types of unmanaged resource are objects that wrap operating system resources, such as files, windows, network connections, or database connections. Although the garbage collector is able to track the lifetime of an object that encapsulates an unmanaged resource, it doesn't know how to release and clean up the unmanaged resource.

If your types use unmanaged resources, you should do the following:

  • Implement the dispose patternarrow-up-right. This requires that you provide an IDisposable.Disposearrow-up-right implementation to enable the deterministic release of unmanaged resources. A consumer of your type calls Disposearrow-up-right when the object (and the resources it uses) is no longer needed. The Disposearrow-up-right method immediately releases the unmanaged resources.

  • Provide for your unmanaged resources to be released in the event that a consumer of your type forgets to call Disposearrow-up-right. There are two ways to do this:

    Implementing a Dispose method

    • The Dispose() overload

      public void Dispose()
      {
         // Dispose of unmanaged resources.
         Dispose(true);
         // Suppress finalization.
         GC.SuppressFinalize(this);
      }

      The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object.Finalizearrow-up-right override. Therefore, the call to the SuppressFinalizearrow-up-right method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.SuppressFinalizearrow-up-right has no effect. Note that the actual work of releasing unmanaged resources is performed by the second overload of the Dispose method.

    • The Dispose(Boolean) overload

      In the second overload, the disposing parameter is a Booleanarrow-up-right that indicates whether the method call comes from a Disposearrow-up-right method (its value is true) or from a finalizer (its value is false).

      The body of the method consists of two blocks of code:

      • A block that frees unmanaged resources. This block executes regardless of the value of the disposing parameter.

      • A conditional block that frees managed resources. This block executes if the value of disposing is true. The managed resources that it frees can include.

      If the method call comes from a finalizer (that is, if disposing is false), only the code that frees unmanaged resources executes. Because the order in which the garbage collector destroys managed objects during finalization is not defined, calling this Disposeoverload with a value of false prevents the finalizer from trying to release managed resources that may have already been reclaimed.

      protected virtual void Dispose(bool disposing)
      {
         //if already was disposed - don't do anything. 
         //Microsoft guidline recuires, that multiple dispose calls won't case Exceptions
         if (disposed) 
            return; 
         
         if (disposing) {
            // Free any other managed objects here.
            //
         }
         
         // Free any unmanaged objects here.
         //
         disposed = true;
      }

Implementation Samples:

Base class

DerivedClass

Last updated