Custom Iterators and Disposable Resources

An entry about c# 3.0 Publication date 16. April 2007 22:13

About a week ago I posted the source code for my DataStore API. Among other cool features, it uses custom iterators when returning data from the database - that is, the Select<T> methods return IEnumerable<T> (the code below has been stripped to show only its basic structure):

public IEnumerable<T> Select<T>(Action<IDbCommand> initializeCommand)
{
using (IDbConnection connection = this.GetConnection())
{
using (IDbCommand command = connection.CreateCommand())
{
initializeCommand.Invoke(command);
connection.Open();
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
                    // ..populate item
yield return item;
}
}
}
}
} 

When I did a presentation at NNUG a few weeks back discussing the implementation of this, someone raised the question of what would happen to the database connection in such a scenario - would it not be left open? Or more generally - what happens with disposable resources within a method that returns a custom iterator?

Well, the answer can be deduced from the fact that IEnumerator inherits IDisposable. Since a custom iterator is basically syntaxical sugar, we can look at the code the compiler emits to find out exactly what is going on beneath the covers. If we look at the compiled assembly (using Reflector), we can see that .NET has generated the iterator class for us:

Notice that it has indeed implemented the Dispose method. If you open it up and inspect it, you'll see that it takes care of disposing the connection, command and reader objects.

So then, we've discovered that using disposable resources within a method that returns a custom iterator is safe. That is, as long as we remember to call the Dispose method on the iterator when we're through with it... So what then, if we were to use the foreach statement? For example:

foreach (Post post in this.DataStore.Select<Post>())
{
// do something
}           

When using a foreach statement, we're basically letting the compiler deal with creating the enumerator and etc. As such, we've not got a reference to it that we can use to call the Dispose method. Not to worry however - if we look at the IL code a foreach statement turns into, we can se that the compiler takes care of that for us:

As a final note, there are a few things to keep in mind when leaving a database connection open within a method that functions as a custom iterator. For example, if we do a foreach and perform heavy work on each item returned, then we'll be leaving the connection open for a long time - which is seldom a good thing. In such a scenario, loading the data from the iterator into a collection of some sort and then performing the heavy operations 'offline' will be a better choice.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Powered by BlogEngine.NET 1.4.5.0

Welcome!

My name is Fredrik Kalseth, and this is my blog - thanks for visiting! I am fortunate enough to work with what I love for a living, and this blog is essentially the biproduct of that.

I work as a senior consultant for Capgemini, and am also an active participant in the Norwegian .NET community, as an avid attendee but also as a speaker (most recently at NNUG and MSDN Live).

As a developer, I have a wide circle of interest. My primary passion is for agile, test-driven development, with focus on best practices and clean code. That said, I also love to work on the frontend, especially with web development.

On Twitter? My handle is fkalseth. On LinkedIn? I`m there too.


Disclaimer

This is a personal blog; any opinions expressed here are my own and do not necessarily reflect those of my employer. All content herein is my own original creation, and as such is protected by copyright law. Unless otherwise stated, all source code posted on this blog is freely usable under the Microsoft Permissive License.

What Readers Talk About

Comment RSS