Excellent question. You do not need to worry about this; the compiler takes care of it for you. Basically, what we do is we put the cleanup code for the finally blocks into a special cleanup method on the generated iterator. When control leaves the caller's foreach block, the compiler generates code which calls the cleanup code on the iterator.
A simplified example:
static IEnumerable<int> GetInts()
{
try { yield return 1; yield return 2;}
finally { Cleanup(); }
}
Your question is basically "Is Cleanup() called in this scenario?"
foreach(int i in GetInts()) { break; }
Yes. The iterator block is generated as a class with a Dispose method that calls Cleanup, and then the foreach loop is generated as something similar to:
{
IEnumerator<int> enumtor = GetInts().GetEnumerator();
try
{
while(enumtor.MoveNext())
{
i = enumtor.Current;
break;
}
}
finally
{
enumtor.Dispose();
}
}
So when the break happens, the finally takes over and the disposer is called.
See my recent series of articles if you want more information about some of the weird corner cases we considered in the design of this feature.
http://blogs.msdn.com/ericlippert/archive/tags/Iterators/default.aspx
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…