Monday, June 16, 2008

Disposable Types

Implement this variation for types that allocate, directly or indirectly, only managed resources, and for which most classes derived from the type will also allocate only managed resources. System.Web.UI.Control is an example. The Web Control base class has no unmanaged resources, and most classes derived from it won't either. This is why it does not need a finalizer. However, it is common for such controls to have other managed resources (SqlConnection, MessageQueue, etc.) that implement IDisposable interface, so it implements IDisposable as well to allow these to be cleaned up early.
Example:
public class DisposableOnly: IDisposable{
MessageQueue queue;
bool disposed = false;

public DisposableOnly(string path){
queue = new MessageQueue(path);
}

public virtual void Dispose(){
if(!disposed){
queue.Dispose();
queue = null;
disposed = true;
}
}

public void SendMessage(string message){
if(disposed){
throw new ObjectDisposedException(this.ToString());
}

queue.Send(message);
}
}

After Dispose() is called, objects are free to throw ObjectDisposedException from any instance method except Dispose(). Dispose() can be called multiple times and should never throw ObjectDisposedException. An alternative is to allow an object to be resurrected by reacquiring resources when a method is called on already disposed object. For example:
public class DisposableResurrectableOnly: IDisposable{
MessageQueue queue;
bool disposed = false;

public DisposableOnly(string path){
queue = new MessageQueue(path);
}

public virtual void Dispose(){
if(!disposed){
queue.Dispose();
queue = null;
disposed = true;
}
}

public void SendMessage(string message){
if(disposed){
Ressurect();
}

queue.Send(message);
}

protected void Ressurect(){
queue = new MessageQueue();
disposed = false;
}
}

Some types may want to provide an additional cleanup method with a domain specific name. For example, SqlConnection class provides the method Close. Such method should just call Dispose().

No comments: