2010-05-27 24 views
5

Tengo 3 TextReaders: una combinación de StreamReaders y StringReader. Conceptualmente, la concatenación de ellos es un documento de texto único.¿Cómo encadenar varios TextReaders juntos?

Quiero llamar a un método (no bajo mi control) que requiere un solo TextReader. ¿Hay alguna forma incorporada o fácil de hacer un TextReader concatenado de varios TextReaders?

(I podía escribir mi propia subclase TextReader, pero se ve como una buena cantidad de trabajo. En ese caso, yo acababa de escribir a todos a un archivo temporal y luego abrirlo con una sola StreamReader.)

¿Existe una solución fácil a esto que me falta?

Respuesta

5

Acabo de lanzar esto juntos, por lo que no es súper robusto (sin manejo de errores, etc.) pero el caso de prueba básico funciona.

Funciona mediante la creación de un método de extensión para TextReader 's que tienen un segundo, y devuelve una nueva clase TextReader el que llama internamente Read() en la primera hasta que se agote, y luego comienza a llamar Read() en el segundo. Puedes encadenar esto indefinidamente.

Para proporcionar una implementación completa de TextReader sólo tiene que poner en práctica Read(), Peek(), Close() y Dispose(). Todos los demás métodos se basan en la implementación específica Read() para funcionar. Por lo tanto, crear tu propio TextReader realmente no es tan malo, como puedes ver a continuación.

Esto también alivia cualquier problema de rendimiento ya que simplemente estamos envolviendo los TextReaders existentes y no los invocamos para realizar la concatenación.

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

Oh, eso es inteligente: solo manipule 2, y use un método de extensión para encadenarlos. – Ken

Cuestiones relacionadas