Welcome to Atalasoft Community Sign in | Help

Making Streams Enumerable

In this post, I’ll show you a quick hack to make Stream objects enumerable.  This is nice because once done, you can treats Streams as C# 2.0 iterators, which lets us play all kinds of fun games with lambda expressions.

First we’ll start with an adapter class to expose IEnumerable<T>:

    public class StreamAsEnumerable : IEnumerable<char>
    {
        StreamReader _reader;
        public StreamAsEnumerable(Stream stm)
        {
            if (stm == null)
                throw new ArgumentNullException("stm");
            if (!stm.CanSeek)
                throw new ArgumentException("stream must be seekable", "stm");
            if (!stm.CanRead)
                throw new ArgumentException("stream must be readable", "stm");
            _reader = new StreamReader(stm);
        }
        public IEnumerator<char> GetEnumerator()
        {
            int c = 0;
            while ((c = _reader.Read()) >= 0)
            {
                yield return (char)c;
            }
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

This is a very straightforward class – inherit from IEnumerable (in this case we’ll take the char flavor to process text), wrap the Stream in a Stream reader and then implement IEnumerator<T>.GetEnumerator and IEnumerable.GetEnumerator().

The GetEnumerator code is straight forward – read a char from the stream reader and if it’s non-negative, yield return it.

In practice, you can start to write code like this:

    StreamAsEnumerable chars = new StreamAsEnumerable(stm);
    int lines = chars.Count(c => c == '\n');

which is a two liner to count all the lines in a stream (note that in production, you should use Environment.NewLine for newline checking, but this passes).

Now imagine instead that you write a version of StreamAsEnumerable that is IEnumerable<string> or IEnumerable<DSLToken> where DSLToken is a class representing a token for a domain specific language.  This would let you write a parser like this:

StreamAsTokenEnumerator tokens = new StreamAsTokenEnumerator(Stream);
foreach (DSLToken token in tokens)
{
    FeedMyDFA(token);
}

all of a sudden, compilers and interpreters feel so much easier.

Published Friday, January 30, 2009 4:02 PM by Steve Hawley

Comments

Wednesday, June 17, 2009 3:10 PM by Steve's Tech Talk

# Even More IEnumerable<T> Fun

This post is going to cover how to use (and abuse) extension methods to make it easier to write compilers

Anonymous comments are disabled