Ответ 1
Из комментариев:
Тогда как этого избежать? Просто добавьте ключевое слово ожидания?
Нет, вы не можете просто сделать это. (И почему ранее предложенный дублированный вопрос не был фактически дубликат и hellip, ваш сценарий отличается от других.) Вам нужно будет отложить удаление до завершения загрузки, но это осложняется вашей необходимостью выполнить еще два заявления программы ( по крайней мере, & hellip; невозможно точно знать без хороший, минимальный, полный пример кода).
Я действительно думаю, что вы должны переключиться на ожидаемый метод WebClient.DownloadFileTaskAsync()
, поскольку это, по крайней мере, упростит реализацию, что упростит сохраните оператор using
.
Вы можете обратиться к другой части проблемы, захватив возвращенный объект Task
и не ожидая его до тех пор, пока не будут выполнены ваши другие операторы программы:
using (WebClient wc = new WebClient()) {
Task task = wc.DownloadFileTaskAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
await task;
}
Таким образом, загрузка может быть запущена, вызывается два других метода, а затем код будет ждать завершения загрузки. Только после его завершения будет выведен блок using
, позволяющий удалять объект WebClient
.
Конечно, в вашей текущей реализации вы, несомненно, обрабатываете соответствующее событие DownloadXXXCompleted
. Если вы хотите, вы можете продолжать использовать объект таким образом. Но IMHO, как только вы перешли на использование await
, гораздо лучше просто поставить после await
код, который необходимо выполнить при завершении операции. Это сохраняет весь код, относящийся к операции, в одном месте и упрощает реализацию.
Если по какой-то причине вы не можете использовать await
, вам придется использовать альтернативный механизм для задержки утилиты WebClient
. Некоторые подходы позволят вам продолжать использовать using
, другие потребуют, чтобы вы вызывали Dispose()
в обработчике события DownloadXXXCompleted
. Без более полного примера кода и четкого объяснения того, почему await
не подходит, было бы невозможно точно сказать, какой будет лучшая альтернатива.
EDIT:
Поскольку вы подтвердили, что у вас нет доступа к await
в текущем коде, вот несколько других опций, совместимых со старым кодом & hellip;
Одна из возможностей - просто ждать в том же потоке после запуска операции:
using (WebClient wc = new WebClient()) {
object waitObject = new object();
lock (waitObject)
{
wc.DownloadFileCompleted += (sender, e) =>
{
lock (waitObject) Monitor.Pulse(waitObject);
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
Monitor.Wait(waitObject);
}
}
(Примечание: можно использовать любую подходящую синхронизацию выше, например, ManualResetEvent
, CountdownEvent
или даже Semaphore
и/или "тонкие" эквиваленты. Я использую Monitor
просто из-за его простоты и эффективность, и принимать, поскольку предоставленные читатели могут приспособиться к своим предпочтительным средствам синхронизации. Одна очевидная причина, по которой можно предпочесть что-то другое, кроме Monitor
, заключается в том, что другие типы методов синхронизации не будут подвергать риску наличие DownloadFileCompleted
обработчик самого события, ожидающий завершения методов SomeMethod1()
и SomeMethod2()
. Неважно, зависит ли это от того, как долго будут проходить эти вызовы методов по сравнению с загрузкой файла.)
Вышеуказанное, однако, заблокирует текущий поток. В некоторых случаях это может быть хорошо, но чаще всего операция запускается в потоке пользовательского интерфейса, и этот поток не должен блокироваться на время операции. В этом случае вам нужно вообще отказаться от using
и просто вызвать Dispose()
из обработчика события завершения:
WebClient wc = new WebClient();
wc.DownloadFileCompleted += (sender, e) =>
{
wc.Dispose();
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();