Return 来自异步方法的 IAsyncEnumerable
Return IAsyncEnumerable from an async method
采取以下方法:
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;
}
}
我想知道最好的做法是什么,上面的代码试图做什么。基本上从 async
方法返回 IAsyncEnumerable
。
对于我自己,我可以想象两种方式:
- 遍历
IAsyncEnumerable
并立即返回结果。
await foreach(var item in Bar())
{
yield return item;
}
- 创建一个可以临时存储
IAsyncEnumerable
的结构,这似乎是更好的解决方案,但仍然有点矫枉过正。
return new AsyncEnumerableHolder<int>(Bar());
public struct AsyncEnumerableHolder<T>
{
public readonly IAsyncEnumerable<T> Enumerable;
public AsyncEnumerableHolder(IAsyncEnumerable<T> enumerable)
{
Enumerable = enumerable;
}
}
有没有更好的方法来实现这种行为?
结构方法行不通。如果您想异步 return 一个 IAsyncEnumerator<T>
值,您 可以 使用 Task<IAsyncEnumerator<T>>
和 return Bar();
。然而,那是不寻常的。在异步可枚举的开头创建一个包含 await SomeAsyncMethod()
的新 IAsyncEnumerator<T>
会自然得多。为此,您应该按照选项 (1) 的建议使用 await
和 yield
:
public async IAsyncEnumerable<int> Foo()
{
await SomeAsyncMethod();
await foreach (var item in Bar())
yield return item;
}
附带说明一下,JavaScript 对于这种 "enumerate this whole sequence into my result sequence" 概念有一个非常好的 yield*
语法,它支持同步和异步序列。 C# 没有这种用于同步或异步序列的语法。
采取以下方法:
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;
}
}
我想知道最好的做法是什么,上面的代码试图做什么。基本上从 async
方法返回 IAsyncEnumerable
。
对于我自己,我可以想象两种方式:
- 遍历
IAsyncEnumerable
并立即返回结果。
await foreach(var item in Bar())
{
yield return item;
}
- 创建一个可以临时存储
IAsyncEnumerable
的结构,这似乎是更好的解决方案,但仍然有点矫枉过正。
return new AsyncEnumerableHolder<int>(Bar());
public struct AsyncEnumerableHolder<T>
{
public readonly IAsyncEnumerable<T> Enumerable;
public AsyncEnumerableHolder(IAsyncEnumerable<T> enumerable)
{
Enumerable = enumerable;
}
}
有没有更好的方法来实现这种行为?
结构方法行不通。如果您想异步 return 一个 IAsyncEnumerator<T>
值,您 可以 使用 Task<IAsyncEnumerator<T>>
和 return Bar();
。然而,那是不寻常的。在异步可枚举的开头创建一个包含 await SomeAsyncMethod()
的新 IAsyncEnumerator<T>
会自然得多。为此,您应该按照选项 (1) 的建议使用 await
和 yield
:
public async IAsyncEnumerable<int> Foo()
{
await SomeAsyncMethod();
await foreach (var item in Bar())
yield return item;
}
附带说明一下,JavaScript 对于这种 "enumerate this whole sequence into my result sequence" 概念有一个非常好的 yield*
语法,它支持同步和异步序列。 C# 没有这种用于同步或异步序列的语法。