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
}
}
}