开发者

Convert Stream to IEnumerable. If possible when "keeping laziness"

开发者 https://www.devze.com 2022-12-26 11:37 出处:网络
I recieve a Stream and need to pass in a IEnumerable to another method. public sta开发者_如何学Ctic void streamPairSwitchCipher(Stream someStream)

I recieve a Stream and need to pass in a IEnumerable to another method.

public sta开发者_如何学Ctic void streamPairSwitchCipher(Stream someStream)
{
    ...
    someStreamAsIEnumerable = ...
    IEnumerable returned = anotherMethodWhichWantsAnIEnumerable(someStreamAsIEnumerable);
    ...
}

One way is to read the entire Stream, convert it to an Array of bytes and pass it in, as Array implements IEnumerable. But it would be much nicer if I could pass in it in such a way that I don't have to read the entire Stream before passing it in.

public static IEnumerable<T> anotherMethodWhichWantsAnIEnumerable<T>(IEnumerable<T> p) {
    ... // Something uninteresting
}


This one reads your stream byte by byte 'on demand':

public static IEnumerable<byte> streamAsIEnumerable(Stream stream)
{
    if (stream == null)
        throw new ArgumentNullException("stream");

    for (; ; )
    {
        int readbyte = stream.ReadByte();
        if (readbyte == -1)
            yield break;
        yield return (byte)readbyte;
    }
}

Or even shorter, and not raising an exception if the stream is null, but just yielding nothing:

public static IEnumerable<byte> streamAsIEnumerable(Stream stream)
{
    if (stream != null)
        for (int i = stream.ReadByte(); i != -1; i = stream.ReadByte())
            yield return (byte)i;
}


I did some experiments on this and wrote something similar to phild:

public static class ExtensionMethods
{
    public static IEnumerable<byte> Bytes(this Stream stm)
    {
        while (true)
        {
            int c = stm.ReadByte();
            if (c < 0)
                yield break;
            yield return (byte)c;
        }
    }

    public static IEnumerable<char> Chars(this TextReader reader)
    {
        while (true)
        {
            int c = reader.Read();
            if (c < 0)
                yield break;
            yield return (char)c;
        }
    }
}

The difference here is that I have added Bytes and Chars to Stream as an extension method which lets me write something like this:

foreach (char c in Console.In.Chars()) { /* ... */ }

And for grins, I wrote an abstract class called TokenizingStateMachine that uses IEnumerable on TextReader to implement IEnumerable so that a simple parser can do something like:

foreach (Token t in stateMachine) {
}
0

精彩评论

暂无评论...
验证码 换一张
取 消