在单个 'using' 语句中嵌套“IDisposable”

Nesting 'IDisposable's in a single 'using' statement

关于在单个 'using' 语句中使用嵌套一次性用品的小问题:我应该写出每个一次性用品的 using 语句,还是可以将它们嵌套成一个?示例:

using( FileStream inFile = new FileStream( "myFile.txt", FileMode.Open ) )
using( GZipStream gzip = new GZipStream( inFile, CompressionMode.Decompress ) )
using( FileStream outFile = new FileStream( "myNewFile.txt", FileMode.CreateNew ) )
{
    gzip.CopyTo( outstream );
}

对比

using( GZipStream gzip = new GZipStream( new FileStream( "myFile.txt", FileMode.Open ), CompressionMode.Decompress ) )
using( FileStream outFile = new FileStream( "myNewFile.txt", FileMode.CreateNew ) )
{
    gzip.CopyTo( outstream );
}

只是想知道当块执行完毕时,来自 "myFile.txt" 的未命名 FileStream 是否被清理,因为它在 GZipStream 的 using 语句中,或者它是否保持打开状态并且需要在之后的某个时间清理.

编辑: 需要说明的是,我不是在询问嵌套 using 语句。我问的是在另一个 IDisposable 的 'using' 语句中创建的 IDisposable 是否会在块的末尾被处理掉。任何关于为什么或为什么不的解释将不胜感激。

简单的回答是否定的 - 您需要包装每个对象。

if when the block is done executing, the unnamed FileStream from "myFile.txt" gets cleaned up because it's in the using statement with the GZipStream

即使两个构造函数都成功,它仍然取决于 'owning' class 的设计。 StreamReader 将关闭其 BaseStream,但许多其他 classes 不会。

您不希望您的代码依赖于如此模糊且易于更改的细节。

这取决于构造函数,GZipStream 在处理它时处理您传入的流,除非您使用接受 bool 的 overloads 之一并传入 trueleaveOpen.

但是,您 运行 这样做是有风险的。如果 GZipStream 抛出 ArgumentException 因为流的 CanRead 属性 是 false 传入的流不会被处理掉。

就我个人而言,我宁愿不依赖 "something not going wrong",而是通常采用防御性编码并使用 3 语句版本。


Edit: Just to be clear, I'm not asking about nesting using statements. I'm asking whether or not an IDisposable that is created inside another IDisposable's 'using' statement will be disposed of at the end of the block. Any explanation on why or why not would be appreciated.

如果这是你的问题,那么答案是:不,只有声明分配给 (using var whatever = ...) 的对象将被释放,创建的任何其他对象都取决于 "outer" 对象将被实施到 "chain call" Dispose() 方法。