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