当我把它传递给IDisposable类时,我需要Dispose流吗?
本文关键字:流吗 类时 Dispose IDisposable | 更新日期: 2023-09-27 18:01:30
我写了一段代码。我想确保我以正确的方式处置一个对象。
我有一个这样的Disposable Class用于从非托管资源中读取一些数据。
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))
{
//...
}
}
这对我来说似乎没问题。后来我注意到类是通过引用传递的,所以如果我处置其中一个,可能就不需要处置另一个了。
我的问题是我可以这样做吗?
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正在访问一些非托管资源,并且您需要在此代码块之后显式调用dispose方法,那么您必须坚持当前的实现。
在第二个实现中,不会为MyFileReader对象调用Dispose方法。(除非你可能在析构函数中调用它,而你不知道什么时候会调用它)
如果你不喜欢嵌套使用,那么你可以选择第二种方法,在MyFileReader类的Dispose()方法实现中,显式地处置流。如果这个流只被MyFileReader使用,那么让MyFileReader管理它的生命周期并处理它是一个很好的实践。
许多框架流包装类都有带leaveOpen
参数的构造函数重载,该参数控制流处理行为。
例如StreamReader
、BinaryReader
、GZipStream
。
也有属性方法,SharpZipLib示例:
using (var zip = new ZipInputStream(stream) { IsStreamOwner = false }) { ... }