How can I make `await …` work with `yield return` (i.e. inside an iterator method)?
ado.net, async-await, c#, generator, yield-return
Solution
As of C# 8, this can be accomplished with IAsyncEnumerable
Modified code:
async IAsyncEnumerable<SomeClass> GetStuff()
{
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn)
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
SomeClass someClass = f(reader); // create instance based on returned row
yield return someClass;
}
}
}
Consume it like this:
await foreach (var stuff in GetStuff())
...
Problem
I have existing code that looks similar to: ``` IEnumerable<SomeClass> GetStuff() { using (SqlConnection conn = new SqlConnection(connectionString)) using (SqlCommand cmd = new SqlCommand(sql, conn) { conn.Open(); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { SomeClass someClass = f(reader); // create instance based on returned row yield return someClass; } } } ``` It seems I could benefit by using `reader.ReadAsync()`. However, if I just modify the one line: ``` while (await reader.ReadAsync()) ``` the compiler informs me that `await` can only be used in methods marked with `async`, and suggests I modify the method signature to be: ``` async Task<IEnumerable<SomeClass>> GetStuff() ``` However, doing that makes `GetStuff()` unusable because: The body of `GetStuff()` cannot be an iterator block because `Task<IEnumerable<SomeClass>>` is not an iterator interface type. I'm sure I am missing a key concept with the async programming model. Questions: - Can I use `ReadAsync()` in my iterator? How? - How can I think about the async paradigm differently so that I understand how it works in this type of situation?