2009-05-26 19 views
60

Se ho la seguente situazione:Ha Stream.Dispose chiamare sempre Stream.Close (e 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(); 
    } 
} 

Posso chiamare MySW.Dispose() e saltare il primo, anche se è previsto? Ci sono implants Stream che non funzionano come previsto (come CryptoStream)?

Se no, allora è il seguente codice solo male:

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

perché stai capitalizzando le variabili locali? Mi fa male la mia povera testa :( – mpen

+1

La convenzione di dove sono è quello di utilizzare capitalizzata con ambito locale e inferiore per params (NewOrderLineItem vs newOrderLineItem) Proprio quello che sono abituato a =) – JasonRShaver

+0

possibile duplicato del [Close e Dispose -., Che a chiama?] (http://stackoverflow.com/questions/61092/close-and-dispose-which-to-call) –

risposta

79

Posso chiamare MySW.Dispose() e saltare il primo anche se è previsto?

Sì, questo è quello che è per.

Esistono implementazioni Ruscello che non funzionano come previsto (come CryptoStream)?

È lecito ritenere che se un oggetto implementa IDisposable, verrà smaltito correttamente.

In caso contrario, sarebbe un bug.

Se no, allora è il seguente codice solo male :

No, questo codice è il modo consigliato di trattare con gli oggetti che implementano IDisposable.

Informazioni più eccellente è nella risposta accettato di Close and Dispose - which to call?

58

ho usato Reflector e ha scoperto che System.IO.Stream.Dispose assomiglia a questo:

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

Stream.Close è implementato da una chiamata a Stream.Dispose o viceversa - in modo che il i metodi sono equivalenti Stream.Close esiste solo perché chiudere un flusso sembra più naturale rispetto allo smaltimento di un flusso.

Inoltre si dovrebbe cercare di evitare le chiamate esplicite a questo metodi e utilizzare l'istruzione using invece al fine di ottenere la gestione delle eccezioni corretta gratuitamente.

3

Sia StreamWriter.Dispose() che Stream.Dispose() rilasciano tutte le risorse contenute negli oggetti. Entrambi chiudono il flusso sottostante.

Il codice sorgente di Stream.Dispose() (si noti che questo è dettagli implementativi quindi non si basano su di esso):

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

StreamWriter.Dispose() (stesso 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 
      } 
     } 
    } 
} 

Ancora, I flussi di solito implicitamente vicino/streamwriters prima di loro smaltimento - penso che sembra più pulito.

3

Tutti flussi standard (FileStream, CryptoStream) tenterà di irrigare quando chiuso/disposta. Penso che puoi fare affidamento su questo per eventuali implementazioni di stream Microsoft.

Di conseguenza, chiudere/smaltimento può generare un'eccezione se il colore non riesce.

Infatti IIRC c'era un bug nell'implementazione .NET 1.0 di FileStream in quanto non riuscirebbe a liberare l'handle di file se il filo genera un'eccezione. Questo problema è stato risolto in .NET 1.1 aggiungendo un blocco try/finally al metodo Dispose (booleano).

21

Come ha detto Daniel Bruckner, Dispose e Close sono effettivamente la stessa cosa.

Tuttavia Stream NON chiama Risciacquo() quando è disposto/chiuso. FileStream (e presumo qualsiasi altro Stream con un meccanismo di memorizzazione nella cache) chiama Flush() quando è eliminato.

Se si estende Stream o MemoryStream ecc dovrai implementare una chiamata a flush() quando disposto/chiuso se è necessario.

+2

L'ho esaminato di recente e, se estendi MemoryStream, probabilmente non devi preoccuparti del flushing. Guardando l'implementazione di Flush per MemoryStream indica che in realtà è un no-op, infatti la documentazione indica "Overrides Flush in modo che non venga eseguita alcuna azione". –

+0

@Mike, se uno stream sta scrivendo direttamente in memoria senza buffering, lo svuotamento non è necessario, se uno stream introduce del buffering su un tipo di flusso altrimenti non bufferizzato, sarà necessaria una chiamata per il flush. – ScottS

+0

Non posso discutere con quello - scusa per aver scavato un post di 2 anni! :) –

3

Per gli oggetti che devono essere chiusi manualmente, ogni sforzo dovrebbe essere fatto per creare l'oggetto in un blocco utilizzando.

//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' 

In questo modo non si può mai accedere in modo non corretto 'flusso' fuori dal contesto della clausola di utilizzo e il file è sempre chiusa.

3

ho guardato nel codice .NET per la classe Stream, aveva il seguente che suggerirebbe che sì è possibile ...

// 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(); 
    } 
Problemi correlati