如何从方法中返回Stream,知道它应该被处理?

Fra*_*tin 22 c# idisposable using stream

我有一个方法,将FileStream作为输入.此方法在for循环内运行.

private void UploadFile(FileStream fileStream)
{
    var stream = GetFileStream();
    // do things with stream
}
Run Code Online (Sandbox Code Playgroud)

我有另一种方法,它创建并返回FileStream:

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

现在第一个方法抛出一个ObjectDisposedException当我尝试访问返回的FileStream时,可能是因为它已经关闭,因为我正在使用" using"来正确处理流.

如果我不使用"using"而是按如下方式使用它,那么FileStream将保持打开状态,循环的下一次迭代(在同一文件上运行)会抛出异常,告知文件已在使用中:

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

如果我使用try-finally块,我在那里关闭流,finally那么它也会抛出ObjectDisposedException.

如何有效地返回文件流并关闭它?

Dou*_*las 28

当您IDisposable从方法返回时,您将把处理它的责任降级为您的调用者.因此,您需要using围绕流的整个使用声明您的块,在您的情况下可能会跨越UploadFile调用.

using (var s = GetFileStream())
    UploadFile(s);
Run Code Online (Sandbox Code Playgroud)


Joe*_*orn 12

问题是,一旦退出GetFileStream()方法,就会释放FileStream对象,使其处于不可用状态.正如其他答案已经指出的那样,您需要using从该方法中删除块,而是将using块放在调用此方法的任何代码周围:

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

using (var stream = GetFileStream())
{
    UploadFile(stream);
}
Run Code Online (Sandbox Code Playgroud)

但是,我想更进一步.你想要一种方法来保护你创建的流,GetFileStream()从一个草率的程序员可能在没有using块的情况下调用方法的情况下,或者至少以某种方式向调用者强烈指示该方法的结果需要用using块包围.因此,我建议这样:

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.
}
Run Code Online (Sandbox Code Playgroud)

请注意,您不一定需要为此创建一个全新的类.您可能已经有一个适合此方法的类,您只需添加IDisposable代码即可.最重要的是,您可以将IDisposable其代码应该用using块包装作为其他程序员的信号.

此外,这会设置您修改类,以便您可以在循环之前创建一次IDisposable对象,并让新类实例跟踪在循环结束时需要处置的所有内容.

  • 这有什么帮助?“Stream”类已经是“IDisposable”。此外,没有什么可以阻止在“using(var io = FileIO())”块中多次调用“io.CreateFileStream(..)”。 (4认同)

Ser*_*rvy 5

如果您有一个需要返回打开文件流的方法,那么该方法的所有调用者都需要负责处理返回的流,因为它在返回之前无法处理该流.