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?

Original source

Related problems