IAsyncEnumerable,从事件处理程序产生

Bar*_*ast 4 c# async-await

我正在尝试使用基于IAsyncEnumerable. 基本上沿着以下路线:

async IAsyncEnumerable<string> ReadAll() 
{
    var reader = new EventBasedReader();
    reader.OnRead => (_, args) => yield return e.Message;
    reader.Start();
    await reader.WaitUntilAllRead();
}
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用,因为它是产生的事件处理程序,这是不允许的。有没有另一种方法可以编写它以使其作为IAsyncEnumerable.

Ste*_*ary 10

使用基于 IAsyncEnumerable 的 API 包装基于事件的异步订阅 API。

这两者不直接兼容。事件是基于推送的,可枚举(包括异步枚举)是基于拉的。

为了跨越这个鸿沟,您需要一个缓冲区——某个地方来保存事件数据,因为它被推送给您,但在下游代码拉取它之前。

我建议使用 Channels 作为缓冲区。如果您的用例允许,您可以使用无界通道:

IAsyncEnumerable<string> ReadAll() 
{
  var reader = new EventBasedReader();
  var buffer = Channel.CreateUnbounded<TMessage>();
  reader.OnRead = async (_, args) => await buffer.Writer.WriteAsync(e.Message);
  reader.Start();
  CompleteBufferWhenEventsAreDone();
  return buffer.Reader.ReadAllAsync();

  async void CompleteBufferWhenEventsAreDone()
  {
    await reader.WaitUntilAllRead();
    buffer.Writer.TryComplete();
  }
}
Run Code Online (Sandbox Code Playgroud)