2010-05-27 9 views
5

Mam 3 TextReaders - połączenie StreamReaders i StringReaders. Konceptualnie ich łączenie jest pojedynczym dokumentem tekstowym.Jak połączyć wiele TextReaderów jednocześnie?

Chcę wywołać metodę (nie pod moją kontrolą), która pobiera pojedynczy TextReader. Czy istnieje jakiś wbudowany lub prosty sposób na utworzenie łączącego się obiektu TextReader z wielu obiektów TextReaders?

(I mógł napisać własny TextReader podklasy, ale wygląda na to sporo pracy. W tym przypadku, to bym po prostu napisz je wszystkie do pliku tymczasowego, a następnie otworzyć go za pomocą jednego StreamReader.)

Czy jest to łatwe rozwiązanie, którego mi brakuje?

Odpowiedz

5

Właśnie rzuciłem to razem, więc nie jest super-solidne (brak obsługi błędów, itp.), Ale podstawowy test działa.

Działa poprzez tworzenie metodę rozszerzenia dla TextReader „s, które biorą na sekundę, i zwraca nową klasę TextReader które wewnętrznie wywołuje Read() na pierwszym dopóki nie skończy się, a następnie rozpoczyna się wywołaniem Read() na sekundę. Możesz łączyć to w nieskończoność.

Aby zapewnić pełną realizację TextReader, wystarczy wdrożyć Read(), Peek(), Close() i Dispose(). Wszystkie inne metody polegają na wykonaniu konkretnej implementacji Read(). Stworzenie własnego TextReader naprawdę nie jest takie złe, jak widać poniżej.

Eliminuje to również obawy dotyczące wydajności, ponieważ po prostu pakujemy istniejące moduły TextReaders i nie wywołujemy ich w celu wykonania konkatenacji.

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(); 
      } 
     } 
    } 
} 
+1

Och, to sprytnie: tylko uchwyt 2 i użyj metody rozszerzenia, aby je połączyć. – Ken