3

私はこの方法を持っています:

public Stream Load(string term)
{
    var url = CreateSearchUrl(term);

    var webRequest = (HttpWebRequest)WebRequest.Create(url);
    var webResponse = webRequest.GetResponse();

    return new GZipStream(webResponse.GetResponseStream(), CompressionMode.Decompress);
}

ご覧のとおり、ストリームを呼び出し元に返しますが、WebRequestがランタイムによって破棄され、返されたストリームが無効になるという点で、これが安全かどうかはわかりません。

それをバイト配列に変換してMemoryStreamを返すことも、WebClientを使用することもできますが、このアイデアは好きではありません=)。

ありがとう!

4

1 に答える 1

3

リソース リークを起こさずに Stream を安全に返す簡単な方法はありません。主な問題は、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
}

おそらく、より良いアプローチは、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));

最後に 1 つ: ご存じないかもしれませんが、HTTP には圧縮のサポートが組み込まれています。詳細については、ウィキペディアを参照してください。HttpWebRequest には、AutomaticDecompressionプロパティによる HTTP 圧縮のサポートが組み込まれています。HTTP 圧縮を使用すると、基本的に圧縮がコードに対して透過的になり、HTTP ツール (ブラウザー、フィドラーなど) との連携も向上します。

于 2012-05-08T23:54:30.887 に答える