Upozornění kompilátoru (úroveň 1) CS4014
Vzhledem k tomu, že toto volání není očekáváno, spuštění aktuální metody pokračuje před dokončením volání. Zvažte použití await
operátoru na výsledek volání.
Aktuální metoda volá asynchronní metodu Task , která vrací nebo a Task<TResult> a nepoužije operátor await na výsledek. Volání asynchronní metody spustí asynchronní úlohu. Vzhledem k tomu, že není použit žádný await
operátor, program pokračuje bez čekání na dokončení úkolu. Ve většině případů toto chování není to, co očekáváte. Jiné aspekty volající metody jsou obvykle závislé na výsledcích volání, nebo se očekává, že volaná metoda bude dokončena dříve, než se vrátíte z metody, která obsahuje volání.
Stejně důležitý problém je to, co se stane s výjimkami, které jsou vyvolány volanou asynchronní metodou. Výjimka, která je vyvolána v metodě, která vrací nebo TaskTask<TResult> je uložena ve vrácené úloze. Pokud nečekáte na úkol nebo explicitně zkontrolujete výjimky, výjimka se ztratí. Pokud úkol čekáte, jeho výjimka se znovu zobrazí.
Osvědčeným postupem je vždy čekat na volání.
Měli byste zvážit potlačení upozornění pouze v případě, že jste si jisti, že nechcete čekat na dokončení asynchronního volání a že volaná metoda nevyvolá žádné výjimky. V takovém případě můžete potlačit upozornění přiřazením výsledku úkolu volání proměnné.
Následující příklad ukazuje, jak způsobit upozornění, jak ho potlačit a jak očekávat volání.
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.");
}
Pokud v příkladu zvolíte Call #1 nebo Call #2, dokončí se asynchronní metoda CalledMethodAsync
po CallingMethodAsync
dokončení volajícího i volajícího. Poslední řádek v následujícím výstupu ukazuje, kdy se volá metoda dokončí. Vstup do obslužné rutiny události, která volá CallingMethodAsync
v úplném příkladu, jsou ve výstupu označeny a ukončeny.
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.
Upozornění kompilátoru můžete také potlačit pomocí direktiv upozornění #pragma.
Příklad
Následující konzolová aplikace obsahuje metody z předchozího příkladu. Následující kroky nastaví aplikaci.
Vytvořte konzolovou aplikaci a pojmenujte ji
AsyncWarning
.V editoru Visual Studio Code zvolte soubor Program.cs .
Nahraďte kód v souboru Program.cs následujícím kódem:
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. }
Stisknutím klávesy F5 program spusťte.
Očekávaný výstup se zobrazí na konci kódu.