I'm trying to wrap an asynchronous subscription API based on events with an API based on IAsyncEnumerable. Basically along the lines of:
async IAsyncEnumerable<string> ReadAll()
{
var reader = new EventBasedReader();
reader.OnRead => (_, args) => yield return e.Message;
reader.Start();
await reader.WaitUntilAllRead();
}
However this doesn't work because it's the event handler that yields, and this isn't allowed. Is there another way I can write this to make it work as an IAsyncEnumerable?
Wrap an asynchronous subscription API based on events with an API based on
IAsyncEnumerable.
Those two are not directly compatible. Events are push-based, and enumerables (including async enumerables) are pull-based.
In order to cross that divide, you need a buffer - some place to hold the event data as it is pushed to you but before the downstream code has pulled it.
I recommend using Channels for buffers. If your use case allows it, you could use an unbounded channel:
IAsyncEnumerable<string> ReadAll()
{
var reader = new EventBasedReader();
var buffer = Channel.CreateUnbounded<string>();
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With