.NET - 使用单个using语句替换嵌套的using语句

时间:2010-10-19 23:15:30

标签: c# .net nested idisposable using

如果您使用嵌套的using语句/资源遇到了一些这样的C#代码:

using (var response = (HttpWebResponse)request.GetResponse())
{
    using (var responseStream = response.GetResponseStream())
    {
        using (var reader = new BinaryReader(responseStream))
        {
            // do something with reader
        }
    }
}

用这样的东西替换它是否安全?

using (var reader = new BinaryReader(((HttpWebResponse)request.GetResponse()).GetResponseStream()))
{
    // do something with reader
}

上面的示例只是嵌套一次性资源的示例,请原谅我,如果它不是完全正确的用法。我很好奇当你处理最外层的资源(在这种情况下是BinaryReader),它是否会为你递归处理它的子节点,或者你是否需要用单独的using语句显式地处理每个“层”?例如。如果你处理BinaryReader,是否应该处理响应流,而后者又会处理响应?考虑到最后一句话让我觉得你确实需要单独的using语句,因为没有办法保证包装器对象会处理内部对象。是吗?

5 个答案:

答案 0 :(得分:13)

你应该只是堆叠你的使用语句 - 它具有你想要的效果:

using (var response = (HttpWebResponse)request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var reader = new BinaryReader(responseStream))
{
    // do something with reader
}

答案 1 :(得分:12)

您需要单独的使用声明。

在你的第二个例子中,只会释放BinaryReader,而不是用于构建它的对象。

为了了解原因,请查看using statement实际执行的操作。它需要您的第二个代码,并执行与以下内容相同的操作:

{
    var reader = new BinaryReader(((HttpWebResponse)request.GetResponse()).GetResponseStream());
    try
    {
      // do something with reader
    }
    finally
    {
        if (reader != null)
            ((IDisposable)reader).Dispose();
    }
}

正如您所看到的,Dispose()Response上永远不会有ResponseStream来电。

答案 2 :(得分:3)

FWIW,这是拼写原始示例的另一种方式,可以满足任何对嵌套的沮丧:

using (var response = (HttpWebResponse)request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var reader = new BinaryReader(responseStream))
{
    // do something with reader
}

读者是否处理流实际上是读者的功能,而不是'使用'。我记得这通常是读者的行为 - 他们取得了流的所有权,并在读者自己关闭时处理它。但我上面提供的表格应该没问题。

答案 3 :(得分:1)

根据文档,BinaryReader.Close将关闭基础流。 http://msdn.microsoft.com/en-us/library/system.io.binaryreader.close.aspx

此外,根据HttpWebResponse的文档,您必须关闭基础流或处置响应。 http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx

所以你提供的第二个例子可行。

答案 4 :(得分:0)

我在其他地方发布了这个,但是用逗号分隔你的声明似乎将每个语句以这种方式分隔为一个新的声明并处理它们。

using (IType1 a = new Type1(), b = new Type1()){}

但这意味着您的对象必须属于同一类型。你可以称之为

using (IDisposable a = new Type1(), b = new Type2()){}

但是当然,你只能访问IDisposable方法,而不会抛出对象,这有点愚蠢。相反,我相信你可以使用

using (var a = new Type1(), b = new Type2()){}

这似乎为您提供了正确类型化的对象引用,允许您访问已分配类型的正确方法,并处理创建的两个对象。如果有人知道我为什么不对,请告诉我,因为这对我有用吗? (我知道这个问题真的很老了,但我自己在寻找这个答案时就能找到它)