Menu

A Gotcha with IDisposable and Enumerator methods

March 24, 2016 - .NET, C#, Programming

I recently stumbled upon an interesting quirk related to handling classes implementing IDisposable within Enumerator methods. In my particular case, I had a function that could accept an SQL Connection, but optionally could default to using the application “standard” connection available via other static methods.

In order to accomplish this, I used an overload pattern, with the base case function accepting a NpgsqlConnection as shown:

and with the overload using the application available connection information. (GetConnection() here opens the connection):

I was finding that I was receiving an Connection exception stating that the connection was not open. After puzzling over it, I found the issue to be a result of how Enumerators work. In particular, it was a result of the use of the overload class to return an IEnumerable from the other function dependent on a Disposable wrapped in a using. The problem is that the IEnumerable is returned to the caller and it is only when that Enumerator is used that the Actual Enumerator function starts executing; at which point the original routine will have already disposed the connection (closing it) leaving the enumerator to throw a exception.

There are a number of workarounds; the one I decided on was to change the base case to a private method that has an additional argument to indicate whether to dispose of the passed in connection. This allows the removal of the using block, and let’s that overload instead simply pass true for that argument to call the private overload. This moves the actual dispose logic to the end of the enumerator block, allowing it to function properly. Additionally, by making it private it means it isn’t visible outside the class, which leaves the API as desired- one which takes a connection, and one which doesn’t but assumes the use of a default connection- and disposes of it properly afterwards.

By way of example, let’s assume a simple Disposable class. This implementation doesn’t actually have unmanaged resources, either itself or within aggregates- so realistically it wouldn’t use IDisposable at all, but I’m sure we can all just pretend it does for the sake of the example:

And now, a small Console program which demonstrates the issue as well as the workaround:

As we can see, the Broken implementation clearly has the Dispose() method called before the first character is even retrieved. I found this to be a very interesting quirk. One could even call it a sort of code diabetes, on account of it being so inexorably linked to the use of syntax sugar.

Have something to say about this post? Comment!