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

时间:2015-07-07 04:57:26

标签: c# using idisposable

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

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

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))
        {
            //...
        }

3 个答案:

答案 0 :(得分:3)

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

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

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

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

替代方法是公开读取按照惯例不希望获得流/读者所有权的内容的方法:

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

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

还有属性方法,SharpZipLib示例:

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