tags:

views:

61

answers:

2

Is there any way in a C# iterator block to provide a block of code which will be run when the foreach ends (either naturally of by being broken out of), say to clean up resources?

The best I have come up with is to use the using construct, which is fine but does need an IDisposable class to do the clean up. For example:

    public static IEnumerable<string> ReadLines(this Stream stream)
    {
        using (StreamReader rdr = new StreamReader(stream))
        {
            string txt = rdr.ReadLine();
            while (txt != null)
            {
                yield return txt;
                txt = rdr.ReadLine();
            }
            rdr.Close();
        }
    }
+3  A: 

try/finally works fine, so long as the caller is using a foreach or manually calls Dispose on the IEnumerator<T>. To be honest, if it's to clean up resources, a using statement is probably going to be the best way of doing it anyway - if you're using a resource which needs cleaning up but doesn't implement IDisposable, that's a concern in itself :)

There are certain restrictions on what you can do in iterator blocks, as explained on Eric Lippert's blog, but it all works very nicely in most cases.

You may find my article about iterator block implementation interesting in terms of how finally is translated.

Jon Skeet
A: 

try/finally works in this case.

public static IEnumerable<string> ReadLines(this Stream stream)
{
    StreamReader rdr = new StreamReader(stream);

    try
    {
        string txt = rdr.ReadLine();
        while (txt != null)
        {
            yield return txt;
            txt = rdr.ReadLine();
        }
        rdr.Close();
    }
    finally
    {
        rdr.Dispose();
    }
}
spoon16