问题
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
IAsyncEnumerableand yielding the result immediately back.
await foreach(var item in Bar())
{
yield return item;
}
- Creating a struct which can store an
IAsyncEnumerabletemporarily, 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