I am implementing a pipeline pattern, the resource, say an image object, will go through the pipeline, and i have no idea how many clients are holding the resource, so what's the better way to dispose the resource?
I think you only really have two options.
1) Someone owns that object, and controls access to it. Therefore, it must dispose of it when it has determined that no one should need it anymore. This is good old manual resource management.
2) You don't dispose it, and have to wait for the GC to collect and call the finalizer on the instance. Any object that implements IDisposable should also have a finalizer that handles the sam elogic if Dispose is not called. If you call dispose, then this extra step does not have to be taken, and GC is more efficient.
The way that springs immediately to mind is to wrap the resource inside some form of reference counting "wrapper" so that you can dispose of it when the reference count has released zero.
Something like this:
public class RefCountingWrapper<T> where T:IDisposable, new()
{
private int referenceCount = 0;
private T resource;
public RefCountingWrapper(T item)
{
resource = item;
}
public T Acquire()
{
referenceCount++;
return resource;
}
public void Release()
{
referenceCount--;
if (referenceCount <= 0)
{
resource.Dispose();
}
}
}
Caveats that apply:
- Anyone that has taken the result of Acquire and holds a reference to it will now hold a reference to something that has been disposed (that said, once they've released it, they shouldn't try and access it!).
- This is vulnerable to people not matching their Acquire's and Release's, thus could cause others to encounter a disposed object inadvertantly. That shouldn't be a massive issue if you control all the code that utilises the resource/calls Acquire/Release though.
- You'll probably want to put some locking round the Acquire/Release methods if there's even the slightest hint of multi-threaded code going near something wrapped by this.
- There's absolutely nothing to stop the code that's using the Acquired resource from calling .Dispose() on the underlying resource