У меня есть 3 TextReaders - комбинация StreamReaders и StringReaders. Концептуально, конкатенация их является единственным текстовым документом.
Я хочу назвать метод (не под моим управлением), который берет единственный TextReader. Есть ли какой-либо встроенный или простой способ сделать конкатенирующий TextReader из нескольких TextReaders?
(Я мог записать свой собственный подкласс TextReader, но он похож на изрядный объем работы. В этом случае я просто записал бы им всем во временный файл и затем открыл бы его с единственным StreamReader.)
Существует ли легкое решение этого, что я отсутствую?
Я просто собрал это вместе, так что это не очень надежно (нет обработки ошибок и т.д.), но основной тестовый пример работает.
Он работает путем создания метода расширения для TextReader
, который занимает секунду, и возвращает новый класс TextReader, который внутренне вызывает Read()
на первом, пока он не закончится, а затем начинает вызывать Read()
на втором. Вы можете повторять эту цепочку бесконечно.
Для полной реализации TextReader
вам нужно реализовать только Read()
, Peek()
, Close()
и Dispose()
. Все остальные методы зависят от конкретной реализации Read()
. Поэтому создание собственного TextReader
на самом деле не так уж плохо, как вы можете видеть ниже.
Это также снижает любые проблемы с производительностью, поскольку мы просто оборачиваем существующие TextReader'ы, а не вызываем их для выполнения конкатенации.
class Program
{
static void Main(string[] args)
{
StringReader first = new StringReader("hello ");
StringReader second = new StringReader("world");
StringReader third = new StringReader("!");
using (var allOfThem = first.Concat(second).Concat(third))
{
//writes "hello world!"
Console.WriteLine(allOfThem.ReadToEnd());
}
Console.Read();
}
}
public static class Extensions
{
public static TextReader Concat(this TextReader first, TextReader second)
{
return new ChainedTextReader(first, second);
}
private class ChainedTextReader : TextReader
{
private TextReader first;
private TextReader second;
private bool readFirst = true;
public ChainedTextReader(TextReader first, TextReader second)
{
this.first = first;
this.second = second;
}
public override int Peek()
{
if (readFirst)
{
return first.Peek();
}
else
{
return second.Peek();
}
}
public override int Read()
{
if (readFirst)
{
int value = first.Read();
if (value == -1)
{
readFirst = false;
}
else
{
return value;
}
}
return second.Read();
}
public override void Close()
{
first.Close();
second.Close();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
first.Dispose();
second.Dispose();
}
}
}
}