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:
1 |
public static IEnumerable<Element> GetElements(String Employee,NpgsqlConnection con) {} |
and with the overload using the application available connection information. (GetConnection() here opens the connection):
1 2 3 4 5 6 7 |
public static IEnumerable<Element> GetElements(String Employee) { using(NpgsqlConnection con = DatabaseLibrary.GetConnection()) { return GetElements(Employee,con); } } |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public class SimpleDispose : IDisposable { public String StringValue { get; protected set; } public SimpleDispose(String pValue) { Console.WriteLine("SimpleDispose Constructor"); StringValue = pValue; } public void Dispose() { Console.WriteLine("SimpleDispose.Dispose() Called"); Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { Console.WriteLine("SimpleDispose.Dispose(bool) Called"); if (disposing) { Console.WriteLine("Disposing Managed Resources"); StringValue = null; } Console.WriteLine("Disposing Unmanaged resources"); } } |
And now, a small Console program which demonstrates the issue as well as the workaround:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
class Program { static void Main(string[] args) { try { foreach (char loopchar in GetCharacters("This is a set of characters")) { Console.WriteLine(loopchar); } Console.WriteLine("Calling Broken Implementation..."); foreach (char loopchar in BrokenGetCharacters("This is a set of characters")) { Console.WriteLine(loopchar); } } catch(Exception exx) { Console.WriteLine(exx.ToString()); } finally { Console.ReadKey(); } } private static IEnumerable<char> GetCharacters(SimpleDispose sd,bool DoDispose) { for (int currchar = 0; currchar < sd.StringValue.Length; currchar++) { yield return sd.StringValue[currchar]; } if(DoDispose) sd.Dispose(); } public static IEnumerable<char> GetCharacters(SimpleDispose sd) { return GetCharacters(sd, false); } public static IEnumerable<char> GetCharacters(String str) { SimpleDispose sd = new SimpleDispose(str); return GetCharacters(sd,true); } public static IEnumerable<char> BrokenGetCharacters(String str) { using(SimpleDispose sd = new SimpleDispose(str)) { return GetCharacters(sd); } } } |
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!