2010-10-20 19 views
28

Quando eseguo l'analisi del codice sul seguente pezzo di codice ottengo questo messaggio:"L'oggetto può essere smaltito più di una volta" Errore

Oggetto 'stream' possono essere smaltiti più di una volta nel metodo 'upload.Page_Load (oggetto, EventArgs) '. Per evitare di generare System.ObjectDisposedException, non chiamare Dispose più di una volta su un oggetto.

using(var stream = File.Open(newFilename, FileMode.CreateNew)) 
using(var reader = new BinaryReader(file.InputStream)) 
using(var writer = new BinaryWriter(stream)) 
{ 
    var chunk = new byte[ChunkSize]; 
    Int32 count; 
    while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
    { 
     writer.Write(chunk, 0, count); 
    } 
} 

Non capisco perché potrebbe essere chiamato due volte e come risolverlo per eliminare l'errore. Qualsiasi aiuto?

+1

Ad oggi, VS2017 lancia CA2202 su ciascuna clausola 'using'. Qualcuno ha bisogno di agire insieme. – ajeh

risposta

6

BinaryReader/BinaryWriter disporrà il flusso sottostante quando si dispone. Non è necessario farlo esplicitamente.

Per risolvere il problema è possibile rimuovere l'utilizzo attorno al flusso stesso.

5

Il tuo scrittore disporrà il tuo stream, sempre.

13

Per illustrare, modifichiamo il codice

using(var stream = File.Open(newFilename, FileMode.CreateNew)) 
{ 
    using(var reader = new BinaryReader(file.InputStream)) 
    { 
     using(var writer = new BinaryWriter(stream)) 
     { 
      var chunk = new byte[ChunkSize]; 
      Int32 count; 
      while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
      { 
       writer.Write(chunk, 0, count); 
      } 
     } // here we dispose of writer, which disposes of stream 
    } // here we dispose of reader 
} // here we dispose a stream, which was already disposed of by writer 

Per evitare questo, basta creare lo scrittore direttamente

using(var reader = new BinaryReader(file.InputStream)) 
    { 
     using(var writer = new BinaryWriter(File.Open(newFilename, FileMode.CreateNew))) 
     { 
      var chunk = new byte[ChunkSize]; 
      Int32 count; 
      while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
      { 
       writer.Write(chunk, 0, count); 
      } 
     } // here we dispose of writer, which disposes of its inner stream 
    } // here we dispose of reader 

edit: tener conto di ciò che Eric Lippert sta dicendo, non ci potrebbe effettivamente essere un momento in cui il flusso viene rilasciato dal finalizzatore solo se BinaryWriter genera un'eccezione. Secondo il codice BinaryWriter, che potrebbe avvenire in tre casi

If (output Is Nothing) Then 
     Throw New ArgumentNullException("output") 
    End If 
    If (encoding Is Nothing) Then 
     Throw New ArgumentNullException("encoding") 
    End If 
    If Not output.CanWrite Then 
     Throw New ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable")) 
    End If 
  • se non è stato specificato un output, vale a dire se il flusso è nullo. Questo non dovrebbe essere un problema dato che un flusso null significa nessuna risorsa da smaltire :)
  • se non hai specificato una codifica. dal momento che non usiamo la forma di costruzione in cui viene specificata la codifica, non ci dovrebbe essere alcun problema neanche qui (non ho guardato in contructor codifica troppo, ma una tabella di codici non valida può buttare)
    • se si don' passare un flusso scrivibile. Questo dovrebbe essere catturati abbastanza rapidamente durante lo sviluppo ...

In ogni caso, buon punto, quindi la modifica :)

+2

Cosa succede se il nuovo BinaryWriter viene lanciato dopo l'apertura del flusso di output? Chi chiude il flusso allora? Nessuno, fino a quando non viene eseguito il finalizzatore. In pratica, ciò non accade molto e in pratica, anche se ciò accada, la conseguenza peggiore è che il file rimane aperto un po 'troppo a lungo. Ma se la tua logica * richiede * che tutte le risorse vengano ripulite in modo aggressivo, indipendentemente dalle pazzesche eccezioni, allora questo codice non è corretto. –

+0

@Eric: sì, certo, ma poiché non c'è modo nelle classi di verificare che il filestream sia già chiuso, non possiamo facilmente tenerne conto. Se avessimo una proprietà Closed() come booleana nello stream, potremmo aggiungere la logica di chiusura al filestream per gestire casi speciali in cui si verifica un'eccezione nel costruttore Binary Writer – samy

+0

In particolare, se utilizzo il codice precedente ed eseguo l'analisi del codice Viene visualizzato il messaggio di errore: chiama System.IDisposable.Dispose sull'oggetto 'File.Open (string.Concat (upload.BaseDir, newId, CS $ <> 8__locals3.suffix), FileMode.CreateNew)' prima di tutti i riferimenti a è fuori portata. –

5

Una corretta attuazione della Dispose viene esplicitamente richiesto di non preoccuparsi se è stato chiamato più di una volta sullo stesso oggetto. Mentre più chiamate a Dispose sono a volte indicative di problemi logici o di codice che potrebbero essere meglio scritti, l'unico modo per migliorare il codice pubblicato originale sarebbe quello di convincere Microsoft ad aggiungere un'opzione a BinaryReader e BinaryWriter che li istruisce a non disporre del loro passato- in streaming (e quindi utilizzare tale opzione). In caso contrario, il codice richiesto per garantire che il file venga chiuso anche se il lettore o lo scrittore getta nel suo costruttore sarebbe sufficientemente brutto che semplicemente lasciare che il file venga eliminato più di una volta sembrerebbe più pulito.

10

Ho faticato con questo problema e ho trovato l'esempio here molto utile.Vi posto il codice per una rapida visualizzazione:

using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate)) 
{ 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     // Use the writer object... 
    } 
} 

Sostituire l'esterno mediante dichiarazione con un try/finally avendo cura di entrambi NULL torrente dopo averlo usato in StreamWriter e controllare per assicurarsi che non è nulla in il finalmente prima di smaltire.

Stream stream = null; 
try 
{ 
    stream = new FileStream("file.txt", FileMode.OpenOrCreate); 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     stream = null; 
     // Use the writer object... 
    } 
} 
finally 
{ 
    if(stream != null) 
     stream.Dispose(); 
} 

Questa operazione ha risolto i miei errori.

+0

E grazie per il link MSDN. – Jedidja

Problemi correlati