2009-05-26 11 views
60

Si tengo la siguiente situación:¿Tiene Stream.Dispose siempre llame Stream.Close (y Stream.Flush)

StreamWriter MySW = null; 
try 
{ 
    Stream MyStream = new FileStream("asdf.txt"); 
    MySW = new StreamWriter(MyStream); 
    MySW.Write("blah"); 
} 
finally 
{ 
    if (MySW != null) 
    { 
     MySW.Flush(); 
     MySW.Close(); 
     MySW.Dispose(); 
    } 
} 

¿Puedo llamar MySW.Dispose() y pasa el Primer pesar de que se proporciona? ¿Hay alguna implementación de Stream que no funcione como se espera (como CryptoStream)?

Si no es así, es el siguiente código justo malo:

using (StreamWriter MySW = new StreamWriter(MyStream)) 
{ 
    MySW.Write("Blah"); 
} 
+49

por qué estás capitalizando sus variables locales? Me duele la cabeza :( – mpen

+1

La convención de donde vengo es utilizar el ámbito local en mayúscula y más bajo para los parámetros (NewOrderLineItem vs newOrderLineItem). Justo a lo que estoy acostumbrado =) – JasonRShaver

+0

posible duplicado de [Cerrar y desechar - que a ¿llamar?] (http://stackoverflow.com/questions/61092/close-and-dispose-which-to-call) –

Respuesta

79

¿Puedo llamar MySW.Dispose() y saltar la cerca, aunque está previsto ?

Sí, para eso es para.

¿Hay implementaciones Stream que no funcionan como se esperaba (como CryptoStream)?

Es seguro asumir que si un objeto implementa IDisposable, se deshará de sí mismo correctamente.

Si no es así, entonces sería un error.

Si no, entonces es la siguiente sólo mala código:

No, ese código es la forma recomendada de tratar con los objetos que implementan IDisposable.

Más información relevante se encuentra en la respuesta aceptada a Close and Dispose - which to call?

58

Solía ​​reflector y encontró que System.IO.Stream.Dispose se parece a esto:

public void Dispose() 
{ 
    this.Close(); 
} 
2

Stream.Close se implementa mediante una llamada a Stream.Dispose o viceversa - lo que la los métodos son equivalentes Stream.Close existe solo porque el cierre de una transmisión suena más natural que la eliminación de una transmisión.

Además, debe intentar evitar las llamadas explícitas a este método y utilizar la instrucción using en su lugar para obtener el control de excepciones correcto de forma gratuita.

3

StreamWriter.Dispose() y Stream.Dispose() liberan todos los recursos que tienen los objetos. Ambos cierran la transmisión subyacente.

El código fuente de Stream.Dispose() (nótese que esto es por lo que los detalles de implementación no se basan en ella):

public void Dispose() 
{ 
    this.Close(); 
} 

StreamWriter.Dispose() (igual que con Stream.Dispose()):

protected override void Dispose(bool disposing) 
{ 
    try 
    { 
     // Not relevant things 
    } 
    finally 
    { 
     if (this.Closable && (this.stream != null)) 
     { 
      try 
      { 
       if (disposing) 
       { 
        this.stream.Close(); 
       } 
      } 
      finally 
      { 
       // Not relevant things 
      } 
     } 
    } 
} 

Aún así, las corrientes generalmente implícita cercanos/streamwriters antes de deshacerse de ellos - Creo que se ve más limpio.

3

Todas las transmisiones estándar (FileStream, CryptoStream) intentarán vaciarse cuando estén cerradas/desechadas. Creo que puede confiar en esto para cualquier implementación de transmisión de Microsoft.

Como resultado, Cerrar/Eliminar puede arrojar una excepción si falla el enjuague.

De hecho, IIRC había un error en la implementación .NET 1.0 de FileStream en el sentido de que no liberaría el identificador del archivo si el flujo arroja una excepción. Esto se solucionó en .NET 1.1 agregando un bloque try/finally al método Dispose (boolean).

21

Como mencionó Daniel Bruckner, Dispose y Close son efectivamente la misma cosa.

Sin embargo, Stream NO llama a Flush() cuando está dispuesto/cerrado. FileStream (y supongo que cualquier otro Stream con un mecanismo de caché) llama a Flush() cuando se desecha.

Si extiende Stream, MemoryStream, etc., deberá implementar una llamada a Flush() cuando se deseche/cierre si es necesario.

+2

Estuve investigando esto recientemente, y si está extendiendo MemoryStream, probablemente no tenga que preocuparse por el enrojecimiento. Ver la implementación de Flush for MemoryStream indica que en realidad es una operación no operativa, de hecho, la documentación indica "Invalida la descarga para que no se realice ninguna acción". –

+0

@Mike, si una secuencia está escribiendo directamente en la memoria sin almacenamiento en memoria intermedia, entonces no es necesario enjuagar, si una secuencia introduce algo de almacenamiento en el búfer encima de una corriente de tipo sin buffer, se necesitará una llamada para vaciar. – ScottS

+0

No puedo discutir con eso, lo siento por desenterrar una publicación de 2 años. :) –

3

Para los objetos que se deben cerrar manualmente, se debe hacer todo lo posible para crear el objeto en un bloque de uso.

//Cannot access 'stream' 
using (FileStream stream = File.Open ("c:\\test.bin")) 
{ 
    //Do work on 'stream' 
} // 'stream' is closed and disposed of even if there is an exception escaping this block 
// Cannot access 'stream' 

De esta manera nunca se puede acceder de forma incorrecta 'arroyo' fuera del contexto de la cláusula de uso y el archivo siempre está cerrada.

3

Miré en la fuente de .NET para la clase Stream, que tenía la siguiente lo que sugeriría que sí se puede ...

// Stream used to require that all cleanup logic went into Close(), 
    // which was thought up before we invented IDisposable. However, we 
    // need to follow the IDisposable pattern so that users can write 
    // sensible subclasses without needing to inspect all their base 
    // classes, and without worrying about version brittleness, from a 
    // base class switching to the Dispose pattern. We're moving 
    // Stream to the Dispose(bool) pattern - that's where all subclasses 
    // should put their cleanup starting in V2. 
    public virtual void Close() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    public void Dispose() 
    { 
     Close(); 
    } 
Cuestiones relacionadas