Avviso del compilatore (livello 1) CS4014
Non è possibile attendere la chiamata, pertanto l'esecuzione del metodo corrente continuerà prima del completamento della chiamata. È possibile applicare l'operatore await
al risultato della chiamata.
Con il metodo corrente viene chiamato un metodo asincrono che restituisce Task o Task<TResult> e non applica l'operatore await al risultato. Con la chiamata al metodo asincrono viene avviata un'attività asincrona. Tuttavia, poiché non viene applicato alcun operatore await
, l'esecuzione del programma continua senza attendere il completamento dell'attività. Nella maggior parte dei casi, questo comportamento non è quello previsto. Di solito altri aspetti del metodo chiamante dipendono dai risultati della chiamata o, come minimo, si prevede che il metodo chiamato venga completato prima della restituzione da parte del metodo contenente la chiamata.
Un problema ugualmente importante riguarda cosa accade alle eccezioni generate nel metodo asincrono chiamato. Un'eccezione generata in un metodo che restituisce Task o Task<TResult> viene archiviata nell'attività restituita. Se non si attende l'attività o si controllano in modo esplicito le eccezioni, l'eccezione viene persa. Se si attende l'attività, la relativa eccezione viene generata di nuovo.
Come procedura consigliata, attendere sempre la chiamata.
Si consideri la possibilità di eliminare l'avviso solo se si è certi che non si desidera attendere il completamento della chiamata asincrona e che il metodo chiamato non generi alcuna eccezione. In tal caso, è possibile eliminare l'avviso assegnando il risultato dell'attività della chiamata a una variabile.
Nell'esempio seguente viene illustrato come generare l'avviso, come eliminarlo e come attendere la chiamata.
static async Task CallingMethodAsync(int millisecondsDelay)
{
Console.WriteLine(" Entering calling method.");
// Call #1.
// Call an async method. Because you don't await it, its completion
// isn't coordinated with the current method, CallingMethodAsync.
// The following line causes warning CS4014.
CalledMethodAsync(millisecondsDelay);
// Call #2.
// To suppress the warning without awaiting, you can assign the
// returned task to a variable. The assignment doesn't change how
// the program runs. However, recommended practice is always to
// await a call to an async method.
// Replace Call #1 with the following line.
// Task delayTask = CalledMethodAsync(millisecondsDelay);
// Call #3
// To contrast with an awaited call, replace the unawaited call
// (Call #1 or Call #2) with the following awaited call. Best
// practice is to await the call.
// await CalledMethodAsync(millisecondsDelay);
Console.WriteLine(" Returning from calling method.");
}
static async Task CalledMethodAsync(int millisecondsDelay)
{
Console.WriteLine(" Entering called method, starting and awaiting Task.Delay.");
await Task.Delay(millisecondsDelay);
Console.WriteLine(" Task.Delay is finished--returning from called method.");
}
Nell'esempio, se si sceglie Call #1 o Call #2, il metodo asincrono senza attesa CalledMethodAsync
termina dopo che il relativo chiamante CallingMethodAsync
e il chiamante del chiamante sono completati. Nell'ultima riga nell'output seguente viene mostrato quando viene completato il metodo chiamato. L'entrata e l'uscita dal gestore eventi tramite cui viene chiamato CallingMethodAsync
nell'esempio completo sono contrassegnate nell'output.
Entering the Click event handler.
Entering calling method.
Entering called method, starting and awaiting Task.Delay.
Returning from calling method.
Exiting the Click event handler.
Task.Delay is finished--returning from called method.
È anche possibile eliminare gli avvisi del compilatore usando le direttive #pragma warning.
Esempio
L'applicazione console seguente contiene i metodi dell'esempio precedente. L'applicazione viene configurata con i passaggi riportati di seguito.
Creare una applicazione console e denominarla
AsyncWarning
.Nell'Editor di codice di Visual Studio scegliere il file Program.cs.
Sostituire il codice in Program.cs con il codice seguente.
using System; using System.Threading.Tasks; namespace AsyncWarning { class Program { static async Task Main() { Console.WriteLine("Entering Main() application entry point."); int millisecondsDelay = 2000; await CallingMethodAsync(millisecondsDelay); Console.WriteLine("Exiting Main() application entry point."); await Task.Delay(millisecondsDelay + 500); } static async Task CallingMethodAsync(int millisecondsDelay) { Console.WriteLine(" Entering calling method."); // Call #1. // Call an async method. Because you don't await it, its completion // isn't coordinated with the current method, CallingMethodAsync. // The following line causes warning CS4014. // CalledMethodAsync(millisecondsDelay); // Call #2. // To suppress the warning without awaiting, you can assign the // returned task to a variable. The assignment doesn't change how // the program runs. However, recommended practice is always to // await a call to an async method. // Replace Call #1 with the following line. //Task delayTask = CalledMethodAsync(millisecondsDelay); // Call #3 // To contrast with an awaited call, replace the unawaited call // (Call #1 or Call #2) with the following awaited call. Best // practice is to await the call. // await CalledMethodAsync(millisecondsDelay); Console.WriteLine(" Returning from calling method."); } static async Task CalledMethodAsync(int millisecondsDelay) { Console.WriteLine(" Entering called method, starting and awaiting Task.Delay."); await Task.Delay(millisecondsDelay); Console.WriteLine(" Task.Delay is finished--returning from called method."); } } // Output with Call #1 or Call #2. (Wait for the last line to appear.) // Entering Main() application entry point. // Entering calling method. // Entering called method, starting and awaiting Task.Delay. // Returning from calling method. // Exiting Main() application entry point. // Task.Delay is finished--returning from called method. // Output with Call #3, which awaits the call to CalledMethodAsync. // Entering Main() application entry point. // Entering calling method. // Entering called method, starting and awaiting Task.Delay. // Task.Delay is finished--returning from called method. // Returning from calling method. // Exiting Main() application entry point. }
Selezionare il tasto F5 per eseguire il programma.
L'output previsto viene visualizzato alla fine del codice.