IAsyncEnumerable 的传递?

Pass-through for IAsyncEnumerable?

我想知道是否有一种方法可以将函数写入 "pass through" IAsyncEnumerable...也就是说,该函数将调用另一个 IAsyncEnumerable 函数并产生所有结果,而无需编写foreach要做吗?

我发现自己经常写这个 Code Pattern。这是一个例子:

async IAsyncEnumerable<string> MyStringEnumerator();

async IAsyncEnumerable<string> MyFunction()
{
   // ...do some code...

   // Return all elements of the whole stream from the enumerator
   await foreach(var s in MyStringEnumerator())
   {
      yield return s;
   }
}

无论出于何种原因(由于分层设计),我的函数 MyFunction 想要调用 MyStringEnumerator,但随后会在没有干预的情况下产生所有内容。我必须继续编写这些 foreach 循环才能做到这一点。如果它是 IEnumerable,我会 return IEnumerable。如果是 C++,我可以写一个宏来完成它。

最佳做法是什么?

If it were an IEnumerable I would return the IEnumerable.

嗯,你可以用 IAsyncEnumerable 做同样的事情(注意 async 被删除):

IAsyncEnumerable<string> MyFunction()
{
 // ...do some code...

 // Return all elements of the whole stream from the enumerator
 return MyStringEnumerator();
}

但是,这里有一个重要的语义考虑因素。调用枚举器方法时,...do some code...立即执行,而当枚举器被枚举时不会

// (calling code)
var enumerator = MyFunction(); // `...do some code...` is executed here
...
await foreach (var s in enumerator) // it's not executed here when getting the first `s`
  ...

对于同步和异步枚举都是如此。

如果你希望...do some code...在枚举器被枚举时执行,那么你需要使用foreach/yield循环来获得延迟执行语义:

async IAsyncEnumerable<string> MyFunction()
{
 // ...do some code...

 // Return all elements of the whole stream from the enumerator
 await foreach(var s in MyStringEnumerator())
   yield return s;
}

如果你也想使用同步可枚举的延迟执行语义,你将不得不在同步世界中使用相同的模式:

IEnumerable<string> ImmediateExecution()
{
 // ...do some code...

 // Return all elements of the whole stream from the enumerator
 return MyStringEnumerator();
}

IEnumerable<string> DeferredExecution()
{
 // ...do some code...

 // Return all elements of the whole stream from the enumerator
 foreach(var s in MyStringEnumerator())
   yield return s;
}

从调用方法返回 Task<IAsyncEnumerable<Obj>> 似乎有效

async IAsyncEnumerable<string> MyStringEnumerator();

async Task<IAsyncEnumerable<string>> MyFunction()
{
    await Something();

    return MyStringEnumerator();
}

然后您需要等待 MyFunction()。所以在异步 foreach 中使用将是

await foreach (string s in await MyFunction()) {}