Async Yield Return thanks to IAsyncEnumerable
General description of yield return:
When you use the yield
return statement in your code, you indicate that the method, operator, or get accessor in which the yield
return keyword appears is an iterator. The yield
return statement will return one element in a collection at a time.
The result returned from a yield
return iterator method can be consumed by using a foreach statement or LINQ query. Each iteration of the foreach loop calls the iterator method. When a yield
return statement is reached in the iterator method, the result is returned and the current location in the iterator method is retained. Upon the execution of the next element in the foreach loop, the iterator method is restarted from the retained location the next time that the iterator method is called.
Standard yield Example:
The following code
IEnumerable<int> GenerateWithoutYield()
{
var i = 0;
var list = new List<int>();
while (i<5)
list.Add(++i);
return list;
}
foreach(var number in GenerateWithoutYield())
Console.WriteLine(number);
can be refactored to make use of the yield
return statement as follows:
IEnumerable<int> GenerateWithYield()
{
var i = 0;
while (i<5)
yield return ++i;
}
foreach(var number in GenerateWithYield())
Console.WriteLine(number);
Async yield return:
When working with asynchronous code using async/await, the use of the yield
return statement requires just a few small adjustments to your code. Using an async yield
return statement requires that the method be asynchronous, making use of async/await.
Usually an async method will return a task. Your first thought when using yield
return in your async method may be to have the method return Task of IEnumerable. However, this is not allowed when using yield
return, instead your async yield
return method must return an IAsyncEnumerable
.
You also cannot await your new async yield
return method that returns an IAsynEnumerable
. Instead, yo must await the foreach statement instead. This is becuase IAsyncEnumerable
does not have a GetAwaiter() method. IAsyncEnumerable
is an async iterator.
Example Code:
private async void ReadTheFile()
{
var path = Path.Combine(Environment.CurrentDirectory, "file.txt");
var lines = GetTxtLinesFromFile(path);
// do something with read-in lines
await foreach (var line in lines)
_listBox.Items.Add(line);
}
async IAsyncEnumerable<string> GetTxtLinesFromFile(string filePath)
{
string line;
StreamReader file = new System.IO.StreamReader(filePath);
while ((line = await file.ReadLineAsync()) != null)
yield return line;
}