Stream.Dispose 是不是总是调用 Stream.Close(和 Stream.Flush)
Posted
技术标签:
【中文标题】Stream.Dispose 是不是总是调用 Stream.Close(和 Stream.Flush)【英文标题】:Does Stream.Dispose always call Stream.Close (and Stream.Flush)Stream.Dispose 是否总是调用 Stream.Close(和 Stream.Flush) 【发布时间】:2010-10-29 00:36:29 【问题描述】:如果我有以下情况:
StreamWriter MySW = null;
try
Stream MyStream = new FileStream("asdf.txt");
MySW = new StreamWriter(MyStream);
MySW.Write("blah");
finally
if (MySW != null)
MySW.Flush();
MySW.Close();
MySW.Dispose();
我可以直接致电MySW.Dispose()
并跳过关闭,即使它已提供?是否有任何未按预期工作的 Stream 实现(如 CryptoStream)?
如果不是,那么下面的代码就是不好的代码:
using (StreamWriter MySW = new StreamWriter(MyStream))
MySW.Write("Blah");
【问题讨论】:
为什么要大写局部变量?它伤害了我可怜的头:( 我的惯例是使用大写的本地作用域,并使用较低的参数(NewOrderLineItem 与 newOrderLineItem)。正是我习惯的 =) Close and Dispose - which to call?的可能重复 @BinaryWorrier,另一个问题更通用,涵盖了许多不同的情况。SqlConnection
展示了 Close
和 Dispose
之间的一些差异,而 Stream
没有。
【参考方案1】:
我可以直接调用 MySW.Dispose() 和 跳过关闭,即使它是 提供?
是的,这就是它的用途。
是否有任何 Stream 实现 不能按预期工作(比如 加密流)?
可以安全地假设,如果一个对象实现了IDisposable
,它会正确地处理自己。
如果没有,那将是一个错误。
如果不是,那么下面的就是不好的 代码:
不,该代码是处理实现 IDisposable
的对象的推荐方法。
更多优秀信息在Close and Dispose - which to call?接受的答案中
【讨论】:
【参考方案2】:我使用Reflector,发现System.IO.Stream.Dispose
是这样的:
public void Dispose()
this.Close();
【讨论】:
【参考方案3】:Stream.Close
是通过调用Stream.Dispose
来实现的,反之亦然——所以这些方法是等价的。 Stream.Close
的存在只是因为关闭流听起来比处理流更自然。
此外,您应该尽量避免显式调用此方法并改用using
语句,以便免费获得正确的异常处理。
【讨论】:
【参考方案4】:StreamWriter.Dispose() 和 Stream.Dispose() 都释放对象持有的所有资源。它们都关闭了底层流。
Stream.Dispose()的源码(注意这是实现细节,不要依赖):
public void Dispose()
this.Close();
StreamWriter.Dispose()(与 Stream.Dispose() 相同):
protected override void Dispose(bool disposing)
try
// Not relevant things
finally
if (this.Closable && (this.stream != null))
try
if (disposing)
this.stream.Close();
finally
// Not relevant things
不过,我通常会在处理流/streamwriters 之前隐式关闭它们 - 我认为它看起来更干净。
【讨论】:
【参考方案5】:所有标准流(FileStream、CryptoStream)都将在关闭/处置时尝试刷新。我认为您可以将其用于任何 Microsoft 流实现。
因此,如果刷新失败,Close/Dispose 会抛出异常。
事实上,IIRC 在 FileStream 的 .NET 1.0 实现中存在一个错误,即如果刷新引发异常,它将无法释放文件句柄。这在 .NET 1.1 中已通过向 Dispose(boolean) 方法添加 try/finally 块来解决。
【讨论】:
【参考方案6】:正如 Daniel Bruckner 所说,Dispose 和 Close 实际上是一回事。
但是 Stream 在处理/关闭时不会调用 Flush()。 FileStream (我假设任何其他具有缓存机制的 Stream )在处置时确实调用了 Flush() 。
如果您正在扩展 Stream 或 MemoryStream 等,则需要在必要时在处置/关闭时实现对 Flush() 的调用。
【讨论】:
我最近正在研究这个,如果你正在扩展 MemoryStream,你可能不需要担心刷新。查看 Flush for MemoryStream 的实现表明它实际上是一个空操作,实际上文档声明“重写 Flush 以便不执行任何操作。”。 @Mike,如果流直接写入内存而没有缓冲,则不需要刷新,如果流在其他未缓冲的流类型之上引入一些缓冲,则需要调用刷新. 对此无可争辩 - 抱歉挖掘了一个 2 年前的帖子! :)【参考方案7】:对于需要手动关闭的对象,应尽一切努力在 using 块中创建对象。
//Cannot access 'stream'
using (FileStream stream = File.Open ("c:\\test.bin"))
//Do work on 'stream'
// 'stream' is closed and disposed of even if there is an exception escaping this block
// Cannot access 'stream'
通过这种方式,人们永远不会在 using 子句的上下文之外错误地访问“流”,并且文件总是被关闭。
【讨论】:
【参考方案8】:我查看了 Stream 类的 .net 源代码,它具有以下内容,这表明是的,您可以...
// Stream used to require that all cleanup logic went into Close(),
// which was thought up before we invented IDisposable. However, we
// need to follow the IDisposable pattern so that users can write
// sensible subclasses without needing to inspect all their base
// classes, and without worrying about version brittleness, from a
// base class switching to the Dispose pattern. We're moving
// Stream to the Dispose(bool) pattern - that's where all subclasses
// should put their cleanup starting in V2.
public virtual void Close()
Dispose(true);
GC.SuppressFinalize(this);
public void Dispose()
Close();
【讨论】:
以上是关于Stream.Dispose 是不是总是调用 Stream.Close(和 Stream.Flush)的主要内容,如果未能解决你的问题,请参考以下文章
拆除 UIViewController 时是不是总是调用 viewDidUnload 和 dealloc?
CoInitialize() 是不是总是在每个 .Net Framework / .Net Core 线程上隐式调用?