何时调用WebResponse.Close()

15
WebResponse response;
try
{                
 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
 request.Timeout = 20000;
 response = request.GetResponse();

 request = (HttpWebRequest)WebRequest.Create(url2);
 response = request.GetResponse();
}
catch(Exception ex)
{
 //do something
}              
finally
{
}

response.Close()应该在哪里调用?

  • 每次try中的GetResponse()之后调用?

  • 最后一次try中的GetResponse()之后调用一次?

  • 在finally块中调用?
4个回答

26

以上都不是正确答案。你应该使用 using 块:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 20000;
using (WebResponse response = request.GetResponse())
{
    using (var stream = response.GetResponseStream())
    {
        using (var reader = new StreamReader(stream))
        {
            var result = reader.ReadToEnd();
            // Do something with result
        }
    }
}

using 块将确保即使出现异常,也会调用 Dispose 方法。Dispose 将执行与 Close 相同的操作。

using (var d = new DisposableClass()){code;}

等同于:

DisposableClass d = null;
try
{
    d = new DisposableClass();
    code;
}
finally
{
    if (d != null)
        ((IDisposable)d).Dispose();
}

1
为了更详细的解释,你可以展示所有这些using语句是如何转换成try/finally语句的 :) 我之所以这么说是因为他问是否应该将其放在finally语句中,而你实际上正在做这件事...显然以一种更清晰/易读的方式。 - Allen Rice
这肯定是可以做到的,而不使用“using”语句块,只需使用标准的try catch finally块即可。 - UpTheCreek
释放 WebResponse 实例是必须的吗?我在 Vs2008 的智能感知中没有看到 dispose。 - Michel van Engelen
当我使用ILSpy(而不是.$$$ Reflector)时,我看到一个IDisposable接口。Dispose唯一要做的事情就是运行Close()。 - Michel van Engelen
@Michel:我不知道。你是在使用VB.NET吗?默认情况下它不会显示所有细节。 - John Saunders
显示剩余2条评论

1

将其放在 finally 块中。根据 MSDN

finally 块对于清理在 try 块中分配的任何资源以及运行必须执行的任何代码非常有用,即使出现异常也是如此。无论 try 块如何退出,控制流始终传递到 finally 块。


但如果他在 finally 中放置 response.Close(),他将会得到一个“未分配变量的使用”错误。 - UpTheCreek

0
请注意,嵌套的using块不需要花括号,这可以提高可读性。因此,John Saunder的代码可以写成:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 20000;
using (WebResponse response = request.GetResponse())
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
    var result = reader.ReadToEnd();
    // Do something with result
}

VS.NET明白这样的嵌套块不需要缩进。顺便提一下,如果您知道响应的编码或者无论如何都要忽略它,WebClient提供了一个更简单的API - 缺少头信息,因此基于头(传输/文本)的编码检测变得不可能,但除此之外,它工作得很好。


1
我认为这会降低可读性。即使是单行if语句,我几乎总是添加大括号,除了像“if(简单条件)return;”这样的罕见情况。 - John Saunders
1
对于短小的代码片段,也许加上这些不必要的大括号和冗余的行会使你的代码变得更长,难以在一个屏幕上完全显示,从而导致你的代码概览性变差。然而,真正的提示应该是缩进,而VS.NET会自动以一种非常清晰的方式进行缩进。 - Eamon Nerbonne

-1
我建议如下:
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com");
            request.Timeout = 20000;
            using (var response = request.GetResponse())
            {
                //Do something with response.
            }


            request = (HttpWebRequest)WebRequest.Create("http://www.bing.com");
            using (var response = request.GetResponse())
            {
                //Do somehing with response
            }
        }
        catch (Exception ex)
        {
            //do something
        }
        finally
        {
        }

1
你肯定需要处理/关闭第一个“request”实例,因为你只是用一个新的实例覆盖了它,你要看垃圾回收器何时处理掉第一个实例。 - Marineio
2
WebRequest没有实现IDisposable。 - John Saunders
这里没有必要使用 finally 块。此外,如果在 catch 中没有实际代码,这个答案可能会给人留下需要在所有代码周围使用 try/catch 的错误印象。 - John Saunders

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接