C# in Depth

Cover of C# in Depth
Order now (3rd edition)

Why would you use a finally block in an iterator?

Chapter 6: Implementing iterators the easy way: 6.2.3

Created: 5/13/2008
Last updated: 5/27/2008

In the book, I explain how finally blocks in iterator blocks work, but I don't actually give a real life case of why they're useful. Fortunately, there's a really nice example which is easy to understand. How many times have you written code like this?

using (TextReader reader = File.OpenText(filename))
{
    string line;
    while ( (line=reader.ReadLine()) != null)
    {
        // Do something with the line
    }
}

I've certainly processed lots of files a line at a time. Wouldn't it be nice to just be able to foreach over the file instead? Enter LineReader...

using System.Collections.Generic;
using System.IO;

public class LineReader : IEnumerable<string>
{
    string filename;

    public LineReader(string filename)
    {
        this.filename = filename;
    }

    public IEnumerator<string> GetEnumerator()
    {
        using (TextReader reader = File.OpenText(filename))
        {
            string line;
            while ( (line=reader.ReadLine()) != null)
            {
                yield return line;
            }
        }
    }
   
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

The using statement is just syntactic sugar for a finally block - so as long as you dispose of the iterator, the file will be closed too. Note how the file isn't even opened until the first call to MoveNext. Now you can write code like this:

foreach (string line in new LineReader("file.txt"))
{
    // Do something with the line
}

Possibly more importantly, you can also use this within LINQ to Objects, processing the sequence of lines in a file just like any other sequence of data items. There's a more fully-featured implementation of LineReader in my Miscellaneous Utility library.