web analytics

How to Implement the IDisposable Interface in C#?

Options

codeling 1602 - 6666
@2016-02-28 22:46:21

It is suggested you follow the below programming pattern when any class want to implement the IDisposable interface. 

// Design pattern for the base class.
// By implementing IDisposable, you are announcing that instances
// of this type allocate scarce resources.
public class BaseResource: IDisposable
{
   // Pointer to an external unmanaged resource.
   private IntPtr handle;
   // Other managed resource this class uses.
   private Component Components;
   // Track whether Dispose has been called.
   private bool disposed = false;

   // Constructor for the BaseResource object.
   public BaseResource()
   {
      // Insert appropriate constructor code here.
   }

   // Implement IDisposable.
   // Do not make this method virtual.
   // A derived class should not be able to override this method.
   public void Dispose()
   {
      Dispose(true);
      // Take yourself off the Finalization queue 
      // to prevent finalization code for this object
      // from executing a second time.
      GC.SuppressFinalize(this);
   }

   // Dispose(bool disposing) executes in two distinct scenarios.
   // If disposing equals true, the method has been called directly
   // or indirectly by a user's code. Managed and unmanaged resources
   // can be disposed.
   // If disposing equals false, the method has been called by the 
   // runtime from inside the finalizer and you should not reference 
   // other objects. Only unmanaged resources can be disposed.
   protected virtual void Dispose(bool disposing)
   {
      // Check to see if Dispose has already been called.
      if(!this.disposed)
      {
         // If disposing equals true, dispose all managed 
         // and unmanaged resources.
         if(disposing)
         {
            // Dispose managed resources.
            Components.Dispose();
         }
         // Release unmanaged resources. If disposing is false, 
         // only the following code is executed.
         CloseHandle(handle);
         handle = IntPtr.Zero;
         // Note that this is not thread safe.
         // Another thread could start disposing the object
         // after the managed resources are disposed,
         // but before the disposed flag is set to true.
         // If thread safety is necessary, it must be
         // implemented by the client.

      }
      disposed = true;         
   }

   // Use C# destructor syntax for finalization code.
   // This destructor will run only if the Dispose method 
   // does not get called.
   // It gives your base class the opportunity to finalize.
   // Do not provide destructors in types derived from this class.
   ~BaseResource()      
   {
      // Do not re-create Dispose clean-up code here.
      // Calling Dispose(false) is optimal in terms of
      // readability and maintainability.
      Dispose(false);
   }

   // Allow your Dispose method to be called multiple times,
   // but throw an exception if the object has been disposed.
   // Whenever you do something with this class, 
   // check to see if it has been disposed.
   public void DoSomething()
   {
      if(this.disposed)
      {
         throw new ObjectDisposedException();
      }
   }
}

// Design pattern for a derived class.
// Note that this derived class inherently implements the 
// IDisposable interface because it is implemented in the base class.
public class MyResourceWrapper: BaseResource
{
   // A managed resource that you add in this derived class.
   private ManagedResource addedManaged;
   // A native unmanaged resource that you add in this derived class.
   private NativeResource addedNative;
   private bool disposed = false;

  // Constructor for this object.
   public MyResourceWrapper()
   {
      // Insert appropriate constructor code here.
   }

   protected override void Dispose(bool disposing)
   {
      if(!this.disposed)
      {
         try
         {
            if(disposing)
            {
               // Release the managed resources you added in
               // this derived class here.
               addedManaged.Dispose();         
            }
            // Release the native unmanaged resources you added
            // in this derived class here.
            CloseHandle(addedNative);
            this.disposed = true;
         }
         finally
         {
            // Call Dispose on your base class.
            base.Dispose(disposing);
         }
      }
   }
}

// This derived class does not have a Finalize method
// or a Dispose method without parameters because it inherits 
// them from the base class.

A type's Dispose method should release all the resources that it owns. It should also release all resources owned by its base types by calling its parent type's Dispose method. The parent type's Dispose method should release all resources that it owns and in turn call its parent type's Dispose method, propagating this pattern through the hierarchy of base types. To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.

A Dispose method should call the GC.SuppressFinalize method for the object it is disposing. If the object is currently on the finalization queue, GC.SuppressFinalize prevents its Finalize method from being called. Remember that executing a Finalize method is costly to performance. If your Dispose method has already done the work to clean up the object, then it is not necessary for the garbage collector to call the object's Finalize method.

In this example, the base class BaseResource implements a public Dispose method that can be called by users of the class. It in turn calls the method virtual Dispose(bool disposing) (virtual Dispose(disposing As Boolean) in Visual Basic). Either true or false is passed depending upon the identity of the caller. The appropriate cleanup code for the object is executed in the virtual Dispose method.

Dispose(bool disposing) executes in two distinct scenarios. If disposing equals true, the method has been called directly or indirectly by a user's code and managed and unmanaged resources can be disposed. If disposing equals false, the method has been called by the runtime from inside the finalizer and only unmanaged resources can be disposed. When an object is executing its finalization code, it should not reference other objects, because finalizers do not execute in any particular order. If an executing finalizer references another object that has already been finalized, the executing finalizer will fail.

The base class provides a Finalize method or destructor as a safeguard in the event that Dispose is not called. The Finalize method calls the Dispose method that takes parameters, passing false. You should not re-create Dispose clean-up code within the Finalize method. Calling Dispose(false) is optimal for code readability and maintainability.

The class MyResourceWrapper illustrates how to derive from a class that implements resource management using Dispose. MyResourceWrapper overrides the virtual Dispose(bool disposing) method and provides clean-up code for the managed and unmanaged resources that it creates. MyResourceWrapper also calls Dispose on its base class BaseResource to make sure that its base gets the opportunity to clean up properly. Note that the derived class MyResourceWrapper does not have a Finalize method or a Dispose method without parameters, because it inherits them from the base class BaseResource.

In the above code pattern, the base class BaseResource implements a public Dispose method that can be called by users of the class. It in turn calls the method virtual Dispose(bool disposing). Either true or false is passed depending upon the identity of the caller. The appropriate cleanup code for the object is executed in the virtual Dispose method.

The protected Dispose(bool disposing) method in the above example does not enforce thread safety because the method cannot be called from a user thread and a finalizer thread at the same time. If you do want enfore thread sfety on this method, you should code this mehtod like the following: 

    private void Dispose(bool disposing)
    {
        lock(this)  //keep from getting threading errors.
        {
	.......
        }
    }
}
@2016-03-01 08:10:40

Any component that contains other objects that implement IDisposable, or handles to native resources, should implement the Dispose(bool) method to properly release those objects' resources when the component itself is being released by its container.

@2016-03-02 12:36:39

When Does a Class Need To Implement System.IDisposable Interface in C#?

As we know, one of the new features inherently available in the .Net framework is automatic garbage collection. The garbage collector is responsible for release the storage for the unreferenced object called garbage.

An important thing to remember about garbage collection is that releasing an object by setting it to null or letting an object variable go out of scope doesn't mean the object will be destroyed immediately. The object won't be destroyed until the garbage collector is triggered to go looking for unused objects.

If an object uses some system resources, such as file, window or network connection, we can't depend on the garbage collector clear those objects, this is because we have no idea when the garbage collector will run. It could be immediately, it could be hours later, or it could even be in conjunction with the program exiting. This is fine for the memory used by our objects, but might present a problem for the system resources in use. For example, the creation of a Bitmap object requires that a file be opened and loaded into memory. This requires file and other system resources. Since such resources can be limited, it is a good idea to release them when you are finished.

The preferred method for doing this is through a Dispose method as part of the IDisposable interface. The IDisposable interface indicates that an object can be disposed of. Typically, instances of objects that support this interface should always call the Dispose method to free any nonmemory resources before the last reference to the object is discarded. This interface is part of the System namespace.
Since the Component class supports the IDisposable interface and is the basis for most classes in the System.Windows.Forms namespace, most objects in the Windows Forms namespace provide a Dispose method for just this purpose.

The following exmaple demonstrates how to implement this interface.

using System;
using System.Drawing;
namespace Manning
{
 namespace MyPhotoAlbum
 {
  /// <summary>
  /// The Photograph class represents a single photo and its properties.
  /// </summary>
  public class Photograph : IDisposable
  {
   private string _fileName;
   private Bitmap _bitmap;
   private static Bitmap _invalidImageBitmap = null;
   
   public Photograph(string fileName)
   {
    _fileName = fileName;
    _bitmap = null;
   }
   public void Dispose()
   {
    if (_bitmap != null && _bitmap != InvalidPhotoImage)
    {
     _bitmap.Dispose();
    }
    _bitmap = null;
   }
   public string FileName
   {
    get { return _fileName; }
   }
   public Bitmap Image
   {
    get
    {
     if (_bitmap == null)
     {
      try
      {
       _bitmap = new Bitmap(_fileName);
      }
      catch
      {
       _bitmap = InvalidPhotoImage;
      }
     }
     return _bitmap;
    }
   }
   public static Bitmap InvalidPhotoImage
   {
    get 
    {
     if (_invalidImageBitmap == null)
     {
      // Create the "bad photo" bitmap
      Bitmap bm = new Bitmap(100, 100);
      Graphics g = Graphics.FromImage(bm);
      g.Clear(Color.WhiteSmoke);
      // Draw a red X
      Pen p = new Pen(Color.Red, 5);
      g.DrawLine(p, 0, 0, 100, 100);
      g.DrawLine(p, 100, 0, 0, 100);
      _invalidImageBitmap = bm;
     }
     return _invalidImageBitmap;
    }
   }
   public bool IsImageValid
   {
    get
    {
     return (_bitmap != InvalidPhotoImage);
    }
   }
   // Object class overrides
   public override bool Equals(object obj)
   {
    if (obj is Photograph)
    {
     Photograph p = (Photograph)obj;
     return (_fileName.ToLower().Equals(p.FileName.ToLower()));
    }
    return false;
   }
   public override int GetHashCode()
   {
    return this.FileName.GetHashCode();
   }
   public override string ToString()
   {
    return this.FileName;
   }
   // end of Photograph class
  }
 }
}
@2016-03-02 12:46:06

When true is passed to Dispose (bool), it means that was called by a client that remembered to properly dispose of any class which implement the IDisposable interface. In this case, the managed resources used in the class will be disposed first, than unmanaged resources will be reclaimed.

A disposing argument of false means that the client forgot to properly dispose of the object and that the .NET Garbage Collector (GC) is calling our object's finalizer. The finalizer is the method that the GC calls when it's about to reclaim the memory associated with the object (called Finalize and defined in Object, the ultimate base class of all .NET classes). Because the GC calls the finalizer at some indeterminate timepotentially long after the component is no longer needed (perhaps hours or days later)the finalizer is a bad place to reclaim resources, but it's better than not reclaiming them at all.

The BaseResource class's finalizer implementation calls the Dispose method, passing a disposing argument of false, which indicates that the object shouldn't touch any of the managed objects it may contain. The other managed objects should remain untouched because the GC may have already disposed of them, and their state is undefined. Consequently, the only resources that should be released at this stage are native resources.

Comments

You must Sign In to comment on this topic.


© 2024 Digcode.com