【问题标题】:using() and dispose with multiple wrapped streamsusing() 并使用多个包装的流进行处理
【发布时间】:2009-08-03 18:47:50
【问题描述】:

如果你正在做例如,你只需要一个 using() 用于最外层的流,我是对的吗

MemoryStream mstr = new MemoryStream();

using(StreamWriter w = new StreamWriter(mstr)) {
    ....
}

由于处理 StreamWriter 也应该处理/关闭底层流,所以不需要这样做?:

using(MemoryStream mstr = new MemoryStream())
using(StreamWriter w = new StreamWriter(mstr)) {
    ....
}

(请注意,这些只是示例,关于如何处理包装的流,而不是寻找替代方案,例如使用 StringWriter 等)

【问题讨论】:

    标签: c# stream dispose


    【解决方案1】:

    从可读性和可维护性的角度来看,将所有相关资源放在它们自己的 using 块中是个好主意。例如在下面的代码中,在最后一个大括号之后,不可能尝试访问mstr,因为它的范围是在它有效的块内:

    using (MemoryStream mstr = new MemoryStream())
    using (StreamWriter w = new StreamWriter(mstr) {
        ....
    }
    
    // cannot attempt to access mstr here
    

    如果你不这样限定它,那么仍然可以在它的有效范围之外访问mstr

    MemoryStream mstr = new MemoryStream();
    using (StreamWriter w = new StreamWriter(mstr) {
        ....
    }
    
    mstr.Write(...); // KABOOM! ObjectDisposedException occurs here!
    

    因此,虽然它可能并不总是必要的(在这种情况下并非如此),但它是一个好主意,因为它既可以阐明并强制执行您对其范围的意图。

    【讨论】:

    • 这真是一个更好的解释。
    【解决方案2】:

    我的经验法则:如果它实现了 IDisposable,请将其丢弃。

    虽然目前(并且可能永远)调用 StreamWriter.Dispose() 关闭底层流,但您将来可能使用的其他流派生类可能不会。此外,它似乎也没有真正调用 Dispose(),因此非 MemoryStreams 可能无法正确处理(尽管我现在想不出任何会遭受这种情况的影响)。

    因此,虽然您可以只安全地处置 StreamWriter,但我发现尽可能始终使用块作为可处置对象是一种更好的做法。

    【讨论】:

    • Stream.Close() 表示“此方法调用 Dispose,指定 true 以释放所有资源。”换句话说,在 Stream 上调用 Close() 会自动在其上调用 Dispose(true)。
    • @R Bemrose 正如我所说,StreamWriter 在底层流上调用 close(而不是 dispose)。底层流在内部调用 dispose 的事实是一个实现细节,我认为所有流都依赖该实现链是一种不好的做法,即使它目前确实有效。就个人而言,我将处理任何实现 IDisposable 的东西,这就是我提出的我的经验法则。同样,这不是必需的。
    • 调用 Dispose 通常与调用 Close 具有相同的效果,以及其他效果,例如抑制 finalize。所以使用“使用”而不是“关闭”是安全的。
    【解决方案3】:

    通过查看 Reflector 中的 StreamWriter.Dispose 方法,看起来底层流已关闭,但未释放。我会将每个流放在一个“使用”块中,以便明确地处理它们。

    【讨论】:

    • 实际上,底层流上的 .Close 调用 this.Dispose() ,因此会自行处理。
    • 这就是它今天所做的,Stan。我不认为这是合同的一部分。
    • @John:我只是在“查看 Reflector”时说,Close 确实调用了 Dispose。我不是说要使用它,我只是说 Reflector 实际显示的内容。
    • @Stan R:我担心有些人阅读这篇文章可能无法区分,因为像你这样的专家将问题提交给 Reflector。
    • @John:Stream.Close 被记录为释放 Stream 正在使用的任何资源:msdn.microsoft.com/en-us/library/system.io.stream.close.aspx 这可能包括其他 Streams。
    【解决方案4】:

    回答您的实际问题。 TextWriter 的 Dispose 方法

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }
    

    它调用受保护的 Dispose 并将 true 传递给它。来自TextWriter.Dispose Method (Boolean)

    当disposing参数为true时, 此方法释放所有资源 由任何托管对象持有 TextWriter 参考资料。 这个方法 调用每个的 Dispose 方法 引用的对象。

    但是,最好的做法是将所有实现 IDisposable 的东西都包装在 using 块中,因为我们不能保证始终使用 true 参数调用受保护的 Dipose 方法。

    【讨论】:

      【解决方案5】:

      始终使用using 块确实是一种更好的做法。

      “总是”,除了一个众所周知的 WCF 代理类案例,其中设计缺陷有时会导致其 Dispose 方法抛出异常,从而丢失原始异常。

      【讨论】:

      • 从来没有遇到过这个错误?链接到文章?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-10
      • 1970-01-01
      • 2021-04-07
      • 2011-10-17
      • 2020-07-09
      • 1970-01-01
      • 2020-01-25
      相关资源
      最近更新 更多