2015-08-17 14 views
9

Ho un metodo che accetta FileStream come input. Questo metodo è in esecuzione all'interno di un ciclo for.Come restituire un flusso da un metodo, sapendo che dovrebbe essere eliminato?

private void UploadFile(FileStream fileStream) 
{ 
    var stream = GetFileStream(); 
    // do things with stream 
} 

ho un altro metodo che crea e restituisce il FileStream:

private FileStream GetFileStream() 
{ 
    using(FileStream fileStream = File.Open(myFile, FileMode.Open)) 
    { 
     //Do something 
     return fileStream; 
    } 
} 

Ora il primo metodo genera un ObjectDisposedException quando provo ad accedere al FileStream tornato, probabilmente perché è già chiuso essendo io utilizzando "using" per disporre correttamente lo stream.

Se non utilizzo "using" e invece lo uso come segue, quindi FileStream rimane aperto e la successiva iterazione del ciclo (che opera sullo stesso file) genera un'eccezione che indica che il file è già in uso:

private FileStream GetFileStream() 
{ 
    FileStream fileStream = File.Open(myFile, FileMode.Open); 
    //Do something 
    return fileStream; 
} 

Se uso un blocco try-fine, in cui chiudo il flusso nella finally poi getta anche l'ObjectDisposedException.

Come restituire efficacemente il flusso di file e chiuderlo?

+2

Non puoi chiuderlo, non il tuo lavoro. Usa i buoni nomi. "Get" non è sufficiente per aiutare il programmatore a capire che ha bisogno di smaltire il flusso, utilizzare invece "Crea". –

risposta

16

Quando si restituisce un IDisposable da un metodo, si sta relegando la responsabilità di eliminarlo dal chiamante. Pertanto, è necessario dichiarare il blocco using per l'intero utilizzo dello stream, che nel tuo caso presume probabilmente la chiamata UploadFile.

using (var s = GetFileStream()) 
    UploadFile(s); 
4

Se si dispone di un metodo che deve restituire un flusso di file aperto, tutti i chiamanti di tale metodo devono assumersi la responsabilità per lo smaltimento del flusso restituito, poiché non può disporre dello stream prima di restituirlo.

4

Il problema è che l'oggetto FileStream è disposta appena uscita dal metodo GetFileStream(), lasciando inutilizzabile. Come già altre risposte indicano, è necessario rimuovere il blocco using da quel metodo e invece mettere il blocco using intorno a qualsiasi codice che chiama questo metodo:

private FileStream GetFileStream() 
{ 
    FileStream fileStream = File.Open(myFile, FileMode.Open); 
    //Do something 
    return fileStream; 
} 

using (var stream = GetFileStream()) 
{ 
    UploadFile(stream); 
} 

Tuttavia, voglio prendere questo un ulteriore passo avanti. Volete un modo per proteggere lo stream creato dal vostro GetFileStream() dal caso in cui un programmatore sciatto potrebbe chiamare il metodo senza un blocco using o almeno in qualche modo indicare ai chiamanti che il risultato di questo metodo deve essere racchiuso in un blocco using . Pertanto, raccomando questo:

public class FileIO : IDisposable 
{ 
    private FileStream streamResult = null; 

    public FileStream GetFileStream(string myFile) 
    { 
     streamResult = File.Open(myFile, FileMode.Open); 
     //Do something 
     return streamResult; 
    } 

    public void Dispose() 
    { 
     if (streamResult != null) streamResult.Dispose();   
    } 

} 

using (var io = FileIO()) 
{ 
    var stream = io.GetFileStream(myFile); 

    // loop goes here. 
} 

Nota che non è necessario creare una classe completamente nuova per questo. Potresti già avere una classe appropriata per questo metodo in cui puoi semplicemente aggiungere il codice IDisposable. La cosa principale è che si desidera utilizzare IDisposable come segnale per altri programmatori che questo codice deve essere incluso con un blocco using.

Inoltre, questo imposta all'utente di modificare la classe in modo da poter creare l'oggetto IDisposable una volta, prima del ciclo, e fare in modo che la nuova istanza di classe tenga traccia di tutto ciò che è necessario disporre alla fine del ciclo.

+1

Questa è un'ottima [email protected] Joel ti dispiacerebbe elaborare un po 'su come 'IDisposable' è usato come segnale per altri programmatori? Come fanno gli altri programmatori a sapere quando istanziano questa classe che dovrebbero avvolgere il loro codice in un blocco 'using'? – jrn

Problemi correlati