繁体   English   中英

当我将它传递给IDisposable类时,我需要Dispose Stream吗?

[英]Do i need to Dispose Stream when i Pass it to IDisposable class?

我写了一段代码。 我想确保我正确地处理对象。

我有一个像这样的Disposable类,它用于从非托管资源中读取一些数据。

class MyFileReader : IDisposable
{
    private readonly FileStream _stream;

    public MyFileReader(FileStream stream)
    {
        _stream = stream;
    }

    public void Dispose()
    {
        _stream.Dispose();
    }
}

目前在我的程序中我处理这样的对象。

        using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            using (MyFileReader reader = new MyFileReader(stream))
            {
                //...
            }
        }

这对我来说似乎没问题。 后来我注意到Classes是通过引用传递的,所以如果我处理其中一个,就没有必要处理另一个了。

我的问题是我能做这样的事吗?

        using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            MyFileReader reader = new MyFileReader(stream);
            // Remove IDisposable from MyFileReader and stream will close after using.
        }

还是这一个?

        FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
        // stream will close after using.
        using (MyFileReader reader = new MyFileReader(stream))
        {
            //...
        }

是的,你可以编写这样的代码。

但是,不,你不应该这样做。

您的类看起来像XxxxReader类,按惯例拥有它们读取的流。 结果,您的MyFileReader应该处理内部流。 当你知道这个物体的寿命结束时,你通常也会期望处理每一个一次性物品。

请注意,有时它会导致对某些对象进行多次Dispose调用(这应该是IDisposable的实现所期望的)。 虽然它有时会导致代码分析警告,但如果通过跳过一些常规尝试“优化”调用Dispose的次数,则优于丢失Dispose调用。

另一种方法是公开读取内容的方法,按照惯例,预期不会取得流/读者的所有权,如:

 using(stream....)
 {
   var result = MyFileReader.ReadFrom(stream);
 }

如果MyFileReader正在访问某些非托管资源,并且您需要在此代码块之后显式调用Disponse方法,那么您必须坚持使用当前的实现。

在第二个实现中,不会为MyFileReader对象调用Dispose方法。 (直到你可能在析构函数中调用它,你不知道什么时候会被调用)

如果您不喜欢嵌套使用,那么您可以使用第二种替代方法并在MyFileReader类的Dispose()方法实现中,显式地处理Stream。 如果此流仅由MyFileReader使用,那么让MyFileReader管理其生命周期并对其进行处理是一个很好的做法。

许多框架流包装类具有构造函数重载,其中leaveOpen参数控制流处理行为。
示例包括StreamReaderBinaryReaderGZipStream

还有属性方法,SharpZipLib示例:

using (var zip = new ZipInputStream(stream) { IsStreamOwner = false }) { ... }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM