从异步方法返回IAsyncEnumerable

30

采用以下方法:

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

对于我自己,我可以想象两种方法:

  1. 迭代 IAsyncEnumerable 并立即将结果 yield 回去。
await foreach(var item in Bar())
{
    yield return item;
}
  1. 创建一个结构体来暂存IAsyncEnumerable,这似乎是更好的解决方案,但仍然有点过度设计。
  • 创建一个结构体可以暂存IAsyncEnumerable,这似乎是更好的解决方案,但仍然有点过度设计。
  • return new AsyncEnumerableHolder<int>(Bar());
    
    public struct AsyncEnumerableHolder<T>
    {
        public readonly IAsyncEnumerable<T> Enumerable;
    
        public AsyncEnumerableHolder(IAsyncEnumerable<T> enumerable)
        {
            Enumerable = enumerable;
        }
    }
    

    有没有更好的方法来实现这个行为?


    1
    很确定 async 希望你返回 voidTaskTask<T>(但是 void 在这种情况下几乎总是错误的选择)。 - Powerlord
    1
    好的,public async IAsyncEnumerable<int> Bar()在语法上是完全有效的。我不确定你想说什么。 - Twenty
    1
    我要说的是,async 仅支持某些返回类型。将 IAsyncEnumerable<T> 作为返回类型应该会导致编译器出错,因为它没有声明 GetAwaiter 方法。 - Powerlord
    这是另一个问题,我绝对需要X,因为我认为它是解决我的问题的答案,然而X不起作用。相反,你应该解释你想要实现什么,肯定有替代方案。 - aybe
    2
    @Powerlord 嗯,IAsyncEnumerable<T>IAsyncEnumerator<T>返回类型在C#8中肯定是受支持的 - 异步流 - Ivan Stoev
    显示剩余2条评论
    1个回答

    43

    结构体方法无法使用。如果您想异步返回 IAsyncEnumerator<T> 值,您可以使用Task<IAsyncEnumerator<T>>return Bar()。但是,这将不寻常。更自然的做法是创建一个新的 IAsyncEnumerator<T>,在异步枚举开始时包含 await SomeAsyncMethod()。为此,您应该像选项(1)所建议的那样使用awaityield

    public async IAsyncEnumerable<int> Foo()
    {
      await SomeAsyncMethod();
      await foreach (var item in Bar())
        yield return item;
    }
    

    顺便提一下,JavaScript有一个非常好的yield*语法,用于实现“将整个序列枚举到我的结果序列中”的概念,它支持同步和异步序列。C#没有这种语法既不支持同步也不支持异步序列。


    5
    谢谢你的话,再重复一遍感觉很不对。我真的希望 yield* 或类似的东西能够到达 C#。 - Twenty
    8
    如果你感兴趣的话,可以关注这个问题:@Twenty: You can follow this issue - Stephen Cleary

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接