我有一个像这样的一次性类 用于从非托管资源中读取一些数据。
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))
{
//...
}
答案 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
参数控制流处理行为
示例包括StreamReader
,BinaryReader
,GZipStream
。
还有属性方法,SharpZipLib示例:
using (var zip = new ZipInputStream(stream) { IsStreamOwner = false }) { ... }