问题
Take the following the methods:
public async IAsyncEnumerable<int> Foo()
{
await SomeAsyncMethod();
return Bar(); // Throws since you can not return values from iterators
}
public async IAsyncEnumerable<int> Bar()
{
for(int i = 0; i < 10; i++)
{
await Task.Delay(100);
yield return i;
}
}
I wonder what the best practice would be, to do, what the code above tries to. Basically returning an IAsyncEnumerable
from an async
method.
For myself I can imagine two ways:
- Iterating over the
IAsyncEnumerable
and yielding the result immediately back.
await foreach(var item in Bar())
{
yield return item;
}
- Creating a struct which can store an
IAsyncEnumerable
temporarily, which seems to be the better solution, but still kind of overkill.
return new AsyncEnumerableHolder<int>(Bar());
public struct AsyncEnumerableHolder<T>
{
public readonly IAsyncEnumerable<T> Enumerable;
public AsyncEnumerableHolder(IAsyncEnumerable<T> enumerable)
{
Enumerable = enumerable;
}
}
Is there any better way to achieve this behavior?
回答1:
The struct approach wouldn't work. If you want to asynchronously return an IAsyncEnumerator<T>
value, you could use Task<IAsyncEnumerator<T>>
with return Bar();
. However, that would be unusual. It would be much more natural to create a new IAsyncEnumerator<T>
that incorporates await SomeAsyncMethod()
at the beginning of the asynchronous enumerable. To do this, you should use await
and yield
as suggested by your option (1):
public async IAsyncEnumerable<int> Foo()
{
await SomeAsyncMethod();
await foreach (var item in Bar())
yield return item;
}
On a side note, JavaScript has a very nice yield*
syntax for this kind of "enumerate this whole sequence into my result sequence" concept, and it supports both synchronous and asynchronous sequences. C# does not have this kind of syntax for either synchronous or asynchronous sequences.
来源:https://stackoverflow.com/questions/59689529/return-iasyncenumerable-from-an-async-method