Подтвердить что ты не робот

Асинхронные методы в использовании оператора

Примечание. Я использую С# в Unity, это означает версию .NET 3.5, поэтому я не могу использовать ключевое слово await или async.

Что произойдет с использованием оператора, когда я поставлю в него метод, который работает асинхронно?

using (WebClient wc = new WebClient()) {
    wc.DownloadFileAsync(urlUri, outputFile);
}
SomeMethod1();
SomeMethod2();

Как вы знаете, после вызова метода DownloadFileAsync() будет вызываться SomeMethod1(), который находится вне блока using, а DownloadFileAsync() по-прежнему работает. Итак, теперь я действительно смущен тем, что произойдет с оператором using и асинхронным методом в этом случае.

Будет ли Dispose() of wc вызываться в нужное время без каких-либо проблем?

Если нет, как мне исправить этот пример?

4b9b3361

Ответ 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();

Ответ 2

System.Net.WebClient содержит событие DownloadFileCompleted. Вы можете добавить обработчик для этого события и избавиться от клиента в это время.