Преобразование потока в IEnumerable. Если возможно, когда "держат лень",
Я получаю поток и должен передать IEnumerable другому методу.
public static void streamPairSwitchCipher(Stream someStream)
{
...
someStreamAsIEnumerable = ...
IEnumerable returned = anotherMethodWhichWantsAnIEnumerable(someStreamAsIEnumerable);
...
}
Один из способов - прочитать весь поток, преобразовать его в массив байтов и передать его, поскольку Array реализует IEnumerable. Но было бы намного лучше, если бы я мог пройти в нем таким образом, что мне не нужно читать весь поток, прежде чем передавать его.
public static IEnumerable<T> anotherMethodWhichWantsAnIEnumerable<T>(IEnumerable<T> p) {
... // Something uninteresting
}
Ответы
Ответ 1
Этот читает ваш байт потока байтом "по запросу":
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;
}
}
Или даже короче и не генерирует исключение, если поток имеет значение null, но ничего не дает:
public static IEnumerable<byte> streamAsIEnumerable(Stream stream)
{
if (stream != null)
for (int i = stream.ReadByte(); i != -1; i = stream.ReadByte())
yield return (byte)i;
}
Ответ 2
Я сделал несколько экспериментов по этому поводу и написал что-то похожее на 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;
}
}
}
Разница здесь в том, что я добавил Bytes и Chars в Stream как метод расширения, который позволяет мне написать что-то вроде этого:
foreach (char c in Console.In.Chars()) { /* ... */ }
И для усмешек я написал абстрактный класс под названием TokenizingStateMachine, который использует IEnumerable в TextReader для реализации IEnumerable, так что простой парсер может делать что-то вроде:
foreach (Token t in stateMachine) {
}