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 becauseTask<IEnumerable<SomeClass>>
is not an iterator interface type.
I'm sure I am missing a key concept with the async programming model.
Questions:
ReadAsync()
in my iterator? How?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())
...