理解 using 语句

Understanding the using statement

我写了两个代码:

代码块 1:

Stream dataStream;
using (var response = (HttpWebResponse)req.GetResponse())
{
    dataStream = response.GetResponseStream();
}

//Open the stream using a StreamReader for easy access
using (var reader = new StreamReader(dataStream))
{
    data = reader.ReadToEnd();
}

代码块 2:

Stream dataStream;
using (var response = (HttpWebResponse)req.GetResponse())
{
    dataStream = response.GetResponseStream();

    //Open the stream using a StreamReader for easy access
    using (var reader = new StreamReader(dataStream))
    {
        data = reader.ReadToEnd();
    }
}

代码块 1 抛出错误:stream is not reachable
虽然从程序上讲,我认为这两个代码的工作原理是一样的。
我在代码块 2 的整个语句中添加了 using 块,它正在工作。
但我很困惑为什么它会在代码块 1 中抛出错误

根据您指定的行为,似乎在处置 HttpWebResponse 时,它会处置响应流。

Rohit,第一个代码块抛出错误,因为一旦关闭 using 子句的大括号,对象就被视为已处理。即对象留给 GC 收集。代码块 1 中的流范围在第二个 using 语句之前已过期。

正确的访问流的方法是第二个代码块。

using 块使您可以轻松正确地使用一次性物品。因此,在 using 语句中初始化的任何内容都将被视为在 using 块之后处理,即使您在 using 语句之外声明变量也是如此。

from msdn:

As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement. The using statement calls the Dispose method on the object in the correct way, and (when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and cannot be modified or reassigned.

A Stream 不是数据块,而是一种从 "somewhere" 读取该数据的方法。 当您处理该响应(通过退出 using 块)时,您会断开与该 "somewhere" 的连接。这意味着您无法再从该流中读取。

你的第二个例子在你读完它之前一直保持连接。

using 语句确保当执行到达最后一个括号 } 时,作用域对象调用了 Dispose 函数,这意味着 HttpWebResponse 对象在第二个 using 块中超出范围.

尽管您已将流保存在 datastream 变量中,但流本身并未被读取,而是在您调用 ReadToEnd() 时完成的。由于 HttpWebResponse 超出范围或 Disposed,因此您将收到收到的异常。

因为 post 编译(在 IL 中),您的代码将转换为以下内容

代码块:1

            HttpWebResponse response=null;
            Stream dataStream;
            try
            {
                response = (HttpWebResponse) req.GetResponse();
                dataStream = response.GetResponseStream();
            }
            finally
            {
                if(response!=null)
                    ((IDisposable)response).Dispose();
            }

            StreamReader reader = null;
            try
            {
                //DataStream is accessed AFTER response object is disposed 
                reader = new StreamReader(dataStream);
                data = reader.ReadToEnd();
            }
            finally
            {
                if(reader!=null)
                    reader.Dispose();
            }

代码块:2

  HttpWebResponse response=null;
            Stream dataStream;
            try
            {
                response = (HttpWebResponse) req.GetResponse();
                dataStream = response.GetResponseStream();

                StreamReader reader = null;
                try
                {
                    //DataStream is accessed while response object is alive, and connected (not disposed)
                    reader = new StreamReader(dataStream);
                    data = reader.ReadToEnd();
                }
                finally
                {
                    if (reader != null)
                        reader.Dispose();
                }
            }
            finally
            {
                if(response!=null)
                    ((IDisposable)response).Dispose();
            }

如您所见,在 CodeBlock1 中,您正在尝试访问试图从 Disposed(和断开连接的)HttWebResponse 对象读取的流。