The problem is what you're asking doesn't actually make much sense. IEnumerable<T>
is a synchronous interface, and returning Task<IEnumerable<T>>
isn't going to help you much, because some thread would have to block waiting for each item, no matter what.
What you actually want to return is some asynchronous alternative to IEnumerable<T>
: something like IObservable<T>
, dataflow block from TPL Dataflow or IAsyncEnumerable<T>
, which is planned to be added to C# 8.0/.Net Core 3.0. (And in the meantime, there are some libraries that contain it.)
Using TPL Dataflow, one way to do this would be:
ISourceBlock<SomeClass> GetStuff() {
var block = new BufferBlock<SomeClass>();
Task.Run(async () =>
{
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
await conn.OpenAsync();
SqlDataReader reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
SomeClass someClass;
// Create an instance of SomeClass based on row returned.
block.Post(someClass);
}
block.Complete();
}
});
return block;
}
You'll probably want to add error handling to the above code, but otherwise, it should work and it will be completely asynchronous.
The rest of your code would then consume items from the returned block also asynchronously, probably using ActionBlock
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…