谁拥有.NET中的包裹流(例如TextWriter)?

时间:2014-04-18 21:53:20

标签: c# .net stream object-lifetime objectdisposedexception

我最近遇到错误“ObjectDisposedException:无法访问已关闭的流”

[ObjectDisposedException: Cannot access a closed Stream.]
    System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) +10184402
    System.Security.Cryptography.CryptoStream.FlushFinalBlock() +114
    System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing) +48

使用格式后的代码:

using (var stream = new MemoryStream())
{
    using (var hashStream = new CryptoStream(stream,
                                    new SHA256Managed(), CryptoStreamMode.Write))
    using (var writer = new TextWriter(hashStream))
    {
        writer.Write("something");
    }
    // ^-- Exception occurs on hashStream Dispose
    //     While naively I assumed that TextWriter.Dispose wouldn't touch the
    //     underlying stream(s).
    return stream.ToArray();
}

因此,引发异常是因为TextWriter的Dispose释放了包装的Stream(hashStream)。我的问题是:

  1. 此约定是否(使用默认构造函数/参数)应用于.NET中的所有流?

    是否有佳能讨论此资源使用模式?例如,可以假设CryptoStream会关闭MemoryStream吗?我知道答案,are other questions specifically about this,但如果有这样的话,我希望根据设计指南来解决。

  2. 这种行为记录在哪里?

    我找不到TextWriter(stream)CryptoStream构造函数中讨论的“所有权” - 当然我只是在查看错误的位置。 (更新:显然我在阅读时失败了,正如其文件80所指出的那样 在TextWriter构造函数文档中记录。)

  3. 编写此类代码的通用方法是什么?

    也就是说,需要读取底层流(在所有操作结束时,因此仍然打开),而所有嵌套流应该完全关闭/刷新 - 一个简单的{{3例如,还不够。

2 个答案:

答案 0 :(得分:5)

the StreamWriter() documentation中特别提到了这一点。

  

当调用StreamWriter.Dispose时,StreamWriter对象在提供的Stream对象上调用Dispose()。

答案 1 :(得分:3)

在阅读using语句C# spec并查看一些已实现的流(内存,文件等)后,我发现默认行为是在调用{{{ 1}}。 在某些流中您可以明确声明您不想处理基础流,例如在Dispose()中:

DeflateStream
  

leaveOpen类型:System.Boolean如果为true,则保持流对象处于打开状态   在处理DeflateStream对象之后;否则,错误。

当然,您可以通过不使用using语句来处理处理,或者实现一个public DeflateStream(Stream stream, CompressionLevel compressionLevel, bool leaveOpen) 类来封装您的流并且不会丢弃底层流。