suppose I have
IEnumerable<string> Foo()
{
try
{
/// open a network connection, start reading packets
while(moredata)
{
yield return packet;
}
}
finally
{
// close connection
}
}
(Or maybe I did a 'using' - same thing). What happens if my caller goes
var packet = Foo().First();
I am just left with a leaked connection. When does the finally get invoked? Or does the right thing always happen by magic
edit with answer and thoughts
My sample and other 'normal' (foreach, ..) calling patterns will work nicely because they dispose of the IEnumerable (actually the IEnumerator returned by GetEnumerator). I must therefore have a caller somewhere thats doing something funky (explicitly getting an enumerator and not disposing it or the like). I will have them shot
the bad code
I found a caller doing
IEnumerator<T> enumerator = foo().GetEnumerator();
changed to
using(IEnumerator<T> enumerator = foo().GetEnumerator())
I am just left with a leaked connection.
No, you're not.
When does the finally get invoked?
When the IEnumerator<T>
is disposed, which First
is going to do after getting the first item of the sequence (just like everyone should be doing when they use an IEnumerator<T>
).
Now if someone wrote:
//note no `using` block on `iterator`
var iterator = Foo().GetEnumerator();
iterator.MoveNext();
var first = iterator.Current;
//note no disposal of iterator
then they would leak the resource, but there the bug is in the caller code, not the iterator block.