c # - нормально ли встраивать «try / catch» в оператор «using» для веб-запроса? Мой код правильный? - PullRequest
6 голосов
/ 01 февраля 2010

Можно ли встраивать «try / catch» в оператор «using» для веб-запроса? Мой код правильный? Вот мои требования:

  1. Хотите использовать оператор "using", чтобы в любом случае освободить ресурсы для HttpWebResponse

    • Но все же хочется сделать некоторые пользовательские вещи, если есть исключение re HttpWebResponse и «response = (HttpWebResponse) request.GetResponse ();» в частности.

Мой исходный код:

        var result = new HttpHeaderInfo();
        HttpWebRequest request = null;
        HttpWebResponse response = null;
        using (response)
        {
            try
            {
                request = (HttpWebRequest)WebRequest.Create(uri);
                request.Method = "HEAD";
                request.KeepAlive = false;
                request.Timeout = Properties.Settings.Default.WebTimeoutDefault;

                response = (HttpWebResponse)request.GetResponse();
                result.LastModified = response.LastModified;
                result.ContentType = response.ContentType;
                result.StatusCode = response.StatusCode;
                result.ContentLength = response.ContentLength;
            }
            catch (Exception ex)
            {
                if (ex is InvalidOperationException ||
                    ex is ProtocolViolationException ||
                    ex is WebException)
                {
                    result.HttpError = ex;
                    result.LastModified = System.DateTime.MinValue;
                    result.ContentType = null;
                }
                else { throw; }
            }

        }

спасибо

Ответы [ 3 ]

10 голосов
/ 01 февраля 2010

Это нормально, но немного избыточно; в общем смысле вы можете легко удалить блок using, добавить блок finally после catch и явно вызвать там Dispose, что уменьшит вложенность в вашем коде.

В более конкретном смысле меня немного беспокоит то, что вы фактически не присваиваете response до тех пор, пока не получите внутри блока using, а явные объявления переменных не нужны и сбивают с толку. в данном контексте. Я бы переписал это как:

HttpHeaderInfo result;
try
{
    var request = (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "HEAD";
    request.KeepAlive = false;
    request.Timeout = Properties.Settings.Default.WebTimeoutDefault;

    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    {
        result = new HttpHeaderInfo();
        result.LastModified = response.LastModified;
        result.ContentType = response.ContentType;
        result.StatusCode = response.StatusCode;
        result.ContentLength = response.ContentLength;
    }
}
catch (WebException ex)
{
    // etc.
}

Это намного понятнее, чем оригинальная форма. Также обратите внимание, что я ловлю WebException, а не общий System.Exception. Вы должны ловить определенные типы исключений вместо того, чтобы перехватывать общие исключения, а затем проверять их тип.

6 голосов
/ 01 февраля 2010

Другие отмечают это как потенциальную проблему, но я хочу поднять ее как очень определенную проблему: ваше утверждение об использовании не приносит вам никакой пользы в данный момент .

Когда вы пишете оператор использования следующим образом:

SomeType x = value1;
using (x)
{
    x = value2;
}

это value1, который будет расположен в конце блока, не value2. В вашем коде response равен нулю, пока не окажется внутри блока; WebResponse в итоге вы получите , а не .

Вы должны увидеть предупреждение об этом следующим образом:

предупреждение CS0728: Возможно неправильное назначение на местный «ответ», который является аргументом оператора использования или блокировки. Уничтожить вызов или разблокировка произойдет по первоначальному значению локального.

Это предупреждение важно - учти его.

Оставляя это в стороне, вполне разумно поместить блок try / catch в оператор using ... но в этом случае он, вероятно, должен быть вне оператора using, что позволит вам инициализировать response переменная в соответствующее время, так что ответ всегда будет расположен. Я также хотел бы рассмотреть возможность использования нескольких блоков catch для вызова общего метода, а не повторного использования «is».

1 голос
/ 01 февраля 2010

Это совершенно нормально. Вы обрабатываете исключение и не хотите, чтобы оно продолжало пузыриться, это нормально, и вложенные блоки try / catch / finally не являются проблемой. (Внутренне «использование», подобное этому, это просто попытка / окончание.)

ОБНОВЛЕНИЕ: прочитайте немного ближе, и я думаю, что вы действительно хотите использовать использование внутри блока 'try' - строка, где вы фактически помещаете объект в переменную 'response', - это то место, где вы хотите, чтобы блок 'using' начинался , Он действительно компилируется как есть?

...