Imagine you have a method that internally uses an IDisposable object (for example a streamreader), and yield returns items as they are read from the file. Like this:
public IEnumerable<YourObject> Read(string filename)
{
using(var filestream = new FileStream(filename, FileMode.Open))
{
using(var reader = new StreamReader(filestream))
{
string line;
while((line = reader.ReadLine()) != null)
{
yield return new YourObject(line);
}
}
}
}
Will the reader and the filestream be disposed when I use LINQ-methods that doesn’t iterate the complete collection?
YourOjbect firstLine = Read("myfile.txt").First();
When you use
yieldkeyword compiler generates nested class, which implementsIEnumerable,IEnumeratorandIDisposableand stores all context data:As you can see, all local variables from context of the yielding method are moved to fields of this generated class. Interesting methods are those which have
m_Finallyin their names:As you can see, these methods dispose your disposable objects (
FileStreamandStreamReader). When the called? At the end of enumerating, or whenDisposeis called:If you look to
First()implementation ofEnumerable, then you’ll see – it callsDisposeafter returning first item:Thus
Disposeof auto-generated class will be called, and all local variables, which require disposing will be disposed by calls tom_Finallymethods.BTW (not about usage with LINQ) if you look at foreach statement implementation you’ll see that enumerator is disposed after enumerating. Thus
Disposeon generated class will be called even in case ofbreakor exception.