沒有簡單的方法來安全地返回流,而沒有資源泄漏。主要問題是處置提供WebResponse:
public Stream Load(string term)
{
var url = CreateSearchUrl(term);
var webRequest = (HttpWebRequest)WebRequest.Create(url);
var webResponse = webRequest.GetResponse(); // whoops this doesn't get disposed!
return new GZipStream(webResponse.GetResponseStream(), CompressionMode.Decompress);
}
閉幕實際上比關閉響應流,因爲關閉WebResponse的隱式地關閉響應流更重要的是WebResponse的。
我知道獲取WebResponse與Stream一起處理的唯一方法是在放置WebResponse(以及GZipStream)時處理GZipStream的裝飾器。雖然這會工作,這是一個相當大量的代碼:
class WebResponseDisposingStream : Stream
{
private readonly WebResponse response;
private readonly Stream stream;
public WebResponseDisposingStream(WebResponse response, Stream stream)
{
if (response == null)
throw new ArgumentNullException("response");
if (stream == null)
throw new ArgumentNullException("stream");
this.response = response;
this.stream = stream;
}
public override void Close()
{
this.response.Close();
this.stream.Close();
}
// override all the methods on stream and delegate the call to this.stream
public override void Flush() { this.stream.Flush(); } // example delegation for Flush()
// ... on and on for all the other members of Stream
}
也許是更好的辦法是繼續傳球方式,其中使用了流的碼傳遞作爲一個代表:
public void Load(string term, Action<Stream> action)
{
var url = CreateSearchUrl(term);
var webRequest = (HttpWebRequest)WebRequest.Create(url);
using (var webResponse = webRequest.GetResponse())
using (var responseStream = webResponse.GetResponseStream())
using (var gzipStream = new GZipStream(responseStream, CompressionMode.Decompress))
{
action(gzipStream);
}
}
現在,調用者只需傳入應該對Stream進行的操作。在下面的長度被打印到控制檯:
Load("test", stream => Console.WriteLine("Length=={0}", stream.Length));
最後一點:如果你不知道,HTTP還內置了支持壓縮。有關更多詳細信息,請參閱Wikipedia。 HttpWebRequest通過AutomaticDecompression屬性內置了對HTTP壓縮的支持。使用HTTP壓縮基本上使得壓縮對你的代碼透明,並且在HTTP工具(瀏覽器,小提琴手等)中也可以更好地工作。
運行時不會處置它。你唯一的問題是與服務器的連接不會被關閉,直到你處置它。 – Will