Last Updated: December 26, 2018
·
1.597K
· njonsson

Dispose C♯ objects that should implement IDisposable but don’t

UPDATE: There's an updated implementation of this in the latest revision of the Gist. The new implementation provides for generic delegation (fast) as well as reflection (slow).


Sometimes while using somebody else’s API you run across a particularly smelly kind of trash:

1. An object allocates unmanaged resources.
2. The object provides a method for deallocating same.
3. The object does not implement System.IDisposable.

An example of this software antipattern is the OpenNETCF.Phone.Sim.Sim class. Its documentation states: “It is not recommended that you have more than one SIM object open in your application at one time.”

This object helpfully proves a Close method, but it does not implement IDisposable. If it did, we could tidy up by writing:

// Unfortunately, this isn't possible.
using (var sim = new OpenNETCF.Phone.Sim.Sim())
{
    // Use the 'sim' variable ...
}

But instead we’re reduced to this:

var sim = new OpenNETCF.Phone.Sim.Sim();
try
{
    // Use the 'sim' variable ...
}
finally
{
    sim.Close();
}

Where’s the sink? I need to wash my hands!

I’ve written a class called Disposer<T> that makes cleaning up dirty trash a less distasteful experience. It makes the using block useful for such objects as OpenNETCF’s Sim:

using (var disposer = new Disposer<OpenNETCF.Phone.Sim.Sim>(new OpenNETCF.Phone.Sim.Sim(), "Close"))
{
    // Use the 'disposer.Object' property ...
}

See? Your hands didn’t even get dirty.

Under the covers Disposer<T> uses reflection to get at the Close method of Sim. There is certainly a performance penalty for using reflection. If you’re calling the same disposal method many times, you can hang onto it and pass it to Disposer<T>:

// (Do this up front somewhere else.)
var closeMethod = typeof(OpenNETCF.Phone.Sim.Sim).GetMethod("Close");

// (Do this many times.)
using (var disposer = new Disposer<OpenNETCF.Phone.Sim.Sim>(OpenNETCF.Phone.Sim.Sim(), closeMethod))
{
    // Use the 'disposer.Object' property ...
}

I wrote this code in a test-driven fashion, so hopefully I’ve managed to keep the bugs away.

Stay healthy!

(I adapted this protip from a weblog post I wrote in September 2011.)

1 Response
Add your response

@keboo, thanks. If you look at the latest revision of my Gist, you’ll see a similar implementation. http://gist.github.com/1198180

over 1 year ago ·