c# - game - ¿Cómo devolver un Stream desde un método, sabiendo que debe eliminarse?
twitch search (3)
Cuando devuelve un IDisposable
de un método, está relegando la responsabilidad de disponerlo a su interlocutor. Por lo tanto, debe declarar su using
bloque en todo el uso de la transmisión, que en su caso supuestamente abarca la llamada UploadFile
.
using (var s = GetFileStream())
UploadFile(s);
Tengo un método que toma FileStream como entrada. Este método se ejecuta dentro de un bucle for.
private void UploadFile(FileStream fileStream)
{
var stream = GetFileStream();
// do things with stream
}
Tengo otro método que crea y devuelve el FileStream:
private FileStream GetFileStream()
{
using(FileStream fileStream = File.Open(myFile, FileMode.Open))
{
//Do something
return fileStream;
}
}
Ahora, el primer método arroja una ObjectDisposedException
cuando intento acceder al FileStream devuelto, probablemente porque ya está cerrado porque estoy usando " using
" para eliminar correctamente la transmisión.
Si no uso "usar" y en su lugar lo uso de la siguiente manera, entonces FileStream permanece abierto y la siguiente iteración del bucle (que opera en el mismo archivo) lanza una excepción que indica que el archivo ya está en uso:
private FileStream GetFileStream()
{
FileStream fileStream = File.Open(myFile, FileMode.Open);
//Do something
return fileStream;
}
Si uso un bloque try-finally, donde cierro la secuencia en el y finally
, también lanza la ObjectDisposedException
.
¿Cómo devolver efectivamente la secuencia de archivos y cerrarla?
El problema es que el objeto FileStream se elimina tan pronto como sale del método GetFileStream()
, dejándolo en un estado inutilizable. Como otras respuestas ya indican, debe eliminar el bloque de using
de ese método y, en su lugar, colocar el bloque de using
alrededor de cualquier código que llame a este método:
private FileStream GetFileStream()
{
FileStream fileStream = File.Open(myFile, FileMode.Open);
//Do something
return fileStream;
}
using (var stream = GetFileStream())
{
UploadFile(stream);
}
Sin embargo, quiero llevar esto un paso más allá. Desea una forma de proteger el flujo creado por su GetFileStream()
del caso en el que un programador descuidado podría llamar al método sin using
un bloque, o al menos de alguna manera indicar a los llamantes que el resultado de este método debe incluirse con un using
bloque. Por lo tanto, recomiendo esto:
public class FileIO : IDisposable
{
private FileStream streamResult = null;
public FileStream CreateFileStream(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.CreateFileStream(myFile);
// loop goes here.
}
Tenga en cuenta que no necesariamente tiene que crear una clase completamente nueva para esto. Es posible que ya tenga una clase adecuada para este método donde solo puede agregar el código IDisposable. Lo principal es que puede usar IDisposable
como una señal para otros programadores de que este código debe incluirse en un bloque de using
.
Además, esto le permite modificar la clase para que pueda crear su objeto IDisposable una vez, antes del bucle, y hacer que la nueva instancia de clase realice un seguimiento de todo lo que necesita para desechar al final del bucle.
Si tiene un método que necesita devolver un flujo de archivo abierto, todos los que llaman a ese método deben asumir la responsabilidad de eliminar el flujo devuelto, ya que no puede deshacerse del flujo antes de devolverlo.