Dai commenti:
E allora come posso evitare questo? Basta aggiungere la parola chiave await?
No, non è possibile solo farlo. (Ed è per questo che la domanda duplicata precedentemente proposta non era in realtà un duplicato e hellip: il tuo scenario è sottilmente differente.) Dovrai posticipare lo smaltimento fino al completamento del download, ma questo è complicato dalla necessità di eseguire altre due istruzioni del programma (almeno & hellip; impossibile sapere con certezza senza a good, minimal, complete code example).
Io faccio che si dovrebbe passare al metodo di awaitable WebClient.DownloadFileTaskAsync()
, in quanto ciò almeno semplificare l'implementazione, rendendo semplice per mantenere la dichiarazione using
.
È possibile affrontare l'altra parte del problema catturando l'tornato Task
oggetto e non in attesa fino a quando dopo tuoi altre dichiarazioni del programma hanno eseguito:
using (WebClient wc = new WebClient()) {
Task task = wc.DownloadFileTaskAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
await task;
}
In questo modo, il download può essere avviato , gli altri due metodi chiamati e quindi il codice attenderà il completamento del download. Solo quando è completato, il blocco using
verrà chiuso, consentendo l'eliminazione dell'oggetto WebClient
.
Naturalmente, nella vostra attuale implementazione si sta senza dubbio gestendo un evento DownloadXXXCompleted
appropriato. Se vuoi, puoi continuare a usare l'oggetto in questo modo. Ma IMHO una volta passato all'utilizzo di await
, è molto meglio semplicemente mettere dopo il await
il codice che deve essere eseguito al termine dell'operazione. Ciò mantiene tutto il codice relativo all'operazione in un unico posto e semplifica l'implementazione.
Se per qualche motivo non è possibile utilizzare await
, allora si dovrà usare qualche meccanismo alternativo per ritardare l'Smaltire la WebClient
.Alcuni approcci ti permetteranno di continuare a utilizzare using
, altri richiederanno di chiamare Dispose()
nel gestore di eventi DownloadXXXCompleted
. Senza un esempio di codice più completo e una chiara spiegazione del motivo per cui await
non è adatto, non sarebbe possibile dire con certezza quale sarebbe l'alternativa migliore.
EDIT:
Dal momento che hai confermato che non si dispone di accesso alla await
nel codice attuale, qui ci sono un paio di altre opzioni compatibili con il vecchio codice & hellip;
Una possibilità è quella di aspettare proprio nello stesso filo dopo l'avvio dell'operazione:
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);
}
}
(Nota: si può utilizzare qualsiasi sincronizzazione idoneo soprastante, come ManualResetEvent
, CountdownEvent
, o anche Semaphore
e/o equivalenti "slim" Io uso Monitor
semplicemente per la sua semplicità ed efficienza, e prendo come i lettori possono regolare per accogliere i loro mezzi preferiti di sincronizzazione.Un'eventuale ragione si potrebbe preferire qualcosa altro di Monitor
è che gli altri tipi di sincronizzazione techni le domande non corrono il rischio di bloccare lo stesso gestore di eventi DownloadFileCompleted
in attesa dei metodi SomeMethod1()
e SomeMethod2()
da completare. Indipendentemente dal fatto che ciò sia importante dipende ovviamente dal tempo di utilizzo di tali metodi rispetto al download del file.)
Quanto sopra, tuttavia, bloccherà il thread corrente. In alcuni casi, ciò può essere corretto, ma molto spesso l'operazione viene avviata nel thread dell'interfaccia utente e tale thread non deve essere bloccato per la durata dell'operazione. In questo caso, si vuole rinunciare using
del tutto e basta chiamare Dispose()
dal gestore di eventi di completamento:
WebClient wc = new WebClient();
wc.DownloadFileCompleted += (sender, e) =>
{
wc.Dispose();
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
Questo non funzionerà. Usa 'await' con' * TaskAsync' – SLaks
@JasonEvans, perché dici di si? poiché OP non sta usando 'await', allora c'è un problema. –
Grazie mille per le risposte, ho fatto questi stupidi errori diverse volte .. Allora come posso evitare questo? Basta aggiungere la parola chiave await? – Jenix