Preferred method for generating an IObservable<String> from a Stream

c#, reactive-programming, system.reactive

Solution

I think you've got a good idea there (turn `Stream` into `Enumerable<string>` then `IObservable<string>`). However, the IEnumerable code can be cleaner:

IEnumerable<string> ReadLines(Stream stream)
{
    using (StreamReader reader = new StreamReader(stream))
    {
        while (!reader.EndOfStream)
            yield return reader.ReadLine();
    }
}

And then for the IObservable:

IObservable<string> ObserveLines(Stream inputStream)
{
    return ReadLines(inputStream).ToObservable(Scheduler.ThreadPool);
}

This is shorter, more readable, and properly disposes of the streams. It's also lazy.

The `ToObservable` extension takes care of catching the `OnNext` events (new lines) as well as the `OnCompleted` event (end of enumerable) and `OnError`.

Problem

As part of our application (in production for about 4 months now) we have a stream of data coming from an external device that we convert to an IObservable Up until now we've been using the following to generate it, and it's been working quite well. ``` IObservable<string> ObserveStringStream(Stream inputStream) { var streamReader = new StreamReader(inputStream); return Observable .Create<string>(observer => Scheduler.ThreadPool .Schedule(() => ReadLoop(streamReader, observer))); } private void ReadLoop(StreamReader reader, IObserver<string> observer) { while (true) { try { var line = reader.ReadLine(); if (line != null) { observer.OnNext(line); } else { observer.OnCompleted(); break; } } catch (Exception ex) { observer.OnError(ex); break; } } } ``` Last night I wondered if there was a way to use the `yield return` syntax to achieve the same result and came up with this: ``` IObservable<string> ObserveStringStream(Stream inputStream) { var streamReader = new StreamReader(inputStream); return ReadLoop(streamReader) .ToObservable(Scheduler.ThreadPool); } private IEnumerable<string> ReadLoop(StreamReader reader) { while (true) { var line = reader.ReadLine(); if (line != null) { yield return line; } else { yield break; } } } ``` It seems to work quite well and it's much cleaner, but I was wondering if there were any pros or cons for one way over the other, or if there was a better way entirely.

Original source