1

Кусок кода был воспитан кем я разговаривал:объектов и вывоз мусора до события запуска

private void DownloadInformation(string id) 
{ 
    using (WebClient wc = new WebClient()) 
    { 
     wc.DownloadStringCompleted += 
      new DownloadStringCompletedEventHandler(DownloadStringCompleted); 
     wc.DownloadStringAsync(new Uri("http://www.fake.com/" + id)); 
    } 
} 

Выше упрощенная версия этого:

enter image description here

(У меня есть разрешение на публикацию изображения.)

Что меня беспокоит о том, что код связан с обработчиком событий, вызывается DownloadStringAsync(), а затем заканчивается блок using, который вызывает Dispose() по адресу WebClient. Есть ли что-либо, что предотвратит удаление WebClient на using и даже сбор мусора до DownloadStringAsync() завершение и DownloadStringCompleted событие запуска?

Там более новый метод, DownloadStringTaskAsync(), который я хотел бы думать, чтобы использовать в сочетании с await:

private async Task DownloadInformation(string id) 
{ 
    using (WebClient wc = new WebClient()) 
    { 
     wc.DownloadStringCompleted += DownloadStringCompleted; 
     await wc.DownloadStringTaskAsync(new Uri("http://www.fake.com/" + id)); 
    } 
} 

Однако, даже тогда ... Я бы в принципе быть пари, что триггеры событий и обработчик вызывается до того, как WebClient отключается.

Неужели я не понимаю жизненный цикл WebClient в этом сценарии или это ужасный дизайн кода?

+2

Вам не нужно событие с 'DownloadStringTaskAsync'. Задача должна содержать окончательные результаты. Другими словами: 'var content = await wc.DownloadStringTaskAsync (...);'. –

+0

@ LasseV.Karlsen Хорошая точка - это определенно позаботится об этой проблеме. С учетом сказанного, я определенно неспокойно отношусь к первому фрагменту кода. –

+4

Первый пример ужасно разбит. Не используйте его. Оставляйте клиента до завершения события. –

ответ

4

WebClient не реализует IDisposable, его базовый класс Component делает.

Класс Component Устанавливает любые обработчики событий, зарегистрированные в свойстве Events, но WebClient не использует это свойство.

Вызов Dispose в WebClient не влияет на любое состояние, управляемое веб-клиентом.

Фактическая обработка внутренних ресурсов осуществляется по частному методу DownloadBits и внутреннему классу DownloadBitsState.

Таким образом, код, который вы показываете, до сих пор не содержит каких-либо эффектов из-за высвобождения ресурсов слишком рано. Однако это связано с детализацией реализации. Это может измениться в будущем.

Из-за рамки отслеживания ожидающих обратных вызовов вам также не нужно беспокоиться о досрочном сборе мусора, как объясняется в this answer, любезно предоставленном Алексеем Левенковым.

+0

Помимо того, что не реализовано собственное 'Dispose()', не существует ли вероятность того, что 'WebClient' все равно получит мусор, собранный до запуска события, так как я не вижу ничего, что бы сохранить его в живых? Или же 'DownloadStringAsync()', который был вызван в 'WebClient', сохраняет свой экземпляр до завершения? Этот метод возвращается, и ничто не ссылается на экземпляр «WebClient». –

+0

Похоже, @AlexeiLevenkov нашел информацию (в комментариях), которая подтверждает, что вы правы! –

3

Событие используется только с DownloadStringAsync, а не с DownloadStringTaskAsync.

С последней задачей является Task<string>, и когда задача завершается, она содержит ответ от загрузки.

Как таковой второй пример можно переписать как это:

private async Task DownloadInformation(string id) 
{ 
    using (WebClient wc = new WebClient()) 
    { 
     string response = await wc.DownloadStringTaskAsync(new Uri("http://www.fake.com/" + id)); 
     // TODO: Process response 
    } 
} 

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

+0

Я бы тоже ожидал ключевое слово async –

+0

Вы правы, позвольте мне исправить это. –

+2

Вторая часть этого ответа неверна («сломанная» часть - это ужасно ужасно выглядит, поскольку она выглядит сломанной). Подробнее обсуждение http://stackoverflow.com/questions/979791/net-do-i-need-to-keep-a-reference-to-webclient-while-downloading-asynchronousl –