C#: использование инструкций с HttpWebRequests/HttpWebResponses

Джон Скит сделал комментарий (через Twitter) на моем код SOApiDotNet (библиотека .NET для предварительной альфа-версии Stack Overflow API):

@ maximz2005 Одна вещь, которую я заметил, быстро просматривая источник: вы не избавляетесь (sic) от WebResponses. используя операторы FTW.

Он указывает, что мне нужно обернуть эти веб-сеансы операторами using. Однако у меня есть вопрос по этому поводу: должен ли я обернуть все это, начиная с HttpWebRequest, или я должен создать WebRequest вне оператора using, а затем обернуть ответ внутри? У меня такое ощущение, что разница в том, что в первом случае оба объекта будут утилизированы - это правильно?

Заранее спасибо.


person Maxim Zaslavsky    schedule 28.12.2009    source источник


Ответы (3)


HttpWebRequest сам по себе не является одноразовым, в отличие от HttpWebResponse. Вы должны обернуть одноразовые ресурсы с помощью, чтобы обеспечить раннюю и решительную очистку. Правильно реализованный шаблон IDisposable позволяет многократно вызывать Dispose без каких-либо проблем, поэтому даже внешний оператор using обертывает ресурс, который во время собственного удаления удаляет внутренний ресурс оператора using, это все еще в порядке.

Пример кода

var request = (HttpWebRequest)WebRequest.Create("example.com"); 
using (var response = (HttpWebResponse)request.GetResponse()) 
{ 
    // Code here 
}
person Dzmitry Huba    schedule 28.12.2009
comment
Так что я должен объявить ..Request снаружи, что ли? - person Maxim Zaslavsky; 28.12.2009
comment
Да, это означает, что вы должны выполнить запрос var = (HttpWebRequest)WebRequest.Create(example.com); using (var response = (HttpWebResponse)request.GetResponse()) { // Код здесь } - person Benjamin Podszun; 28.12.2009
comment
@Дмитрий, @Бенджамин. Я добавил к вашему ответу пример кода Бенджамина. - person Jan Jongboom; 28.12.2009

Все, что заключено в блок using () {} (то есть внутри первых квадратных скобок), удаляется, когда вы выходите из области видимости.

Я пока не использовал вашу библиотеку (хотя кажется неплохой), но я бы сказал, что вы должны явно удалять каждый IDisposable, который вы создаете (= за который отвечаете), и не возвращаться к вызывающей стороне.

Примечание, так как я видел много людей, борющихся с несколькими вещами, чтобы избавиться: вместо

using (var foo = SomeIDisposable) {
  using (var bar = SomeOtherIDisposable) {
  }
}

который требует много вертикального пространства, которое вы можете написать

using (var foo = SomeIDisposable)
using (var bar = SomeOtherIDisposable) {
}
person Benjamin Podszun    schedule 28.12.2009
comment
Ваш второй абзац (верный, я считаю) противоречит первому. Если все внутри блока использования удалено, вам не понадобится внутренний оператор использования. - person Tomas; 28.12.2009
comment
Смотрите мой обновленный пост: все внутри использования (...) удаляется, когда вы покидаете следующий блок (эта часть: {...}) - person Benjamin Podszun; 28.12.2009

Чтобы предотвратить утечку памяти, вы должны вызывать Dispose для каждого объекта, который реализует IDisposable. Вы можете убедиться, что метод Dispose вызывается с помощью ключевого слова using (без каламбура), поскольку это просто синтаксический сахар для блока try-finally.

person Giorgi    schedule 28.12.2009