Aviso do compilador (nível 1) CS4014

Como essa chamada não é esperada, a execução do método atual continua antes que a chamada seja concluída. Considere aplicar o await operador ao resultado da chamada.

O método atual chama um método assíncrono que retorna a Task ou a Task<TResult> e não aplica o operador await ao resultado. A chamada para o método assíncrono inicia uma tarefa assíncrona. No entanto, como nenhum await operador é aplicado, o programa continua sem esperar que a tarefa seja concluída. Na maioria dos casos, esse comportamento não é o que você espera. Normalmente, outros aspetos do método de chamada dependem dos resultados da chamada ou, minimamente, espera-se que o método chamado seja concluído antes que você retorne do método que contém a chamada.

Uma questão igualmente importante é o que acontece com as exceções que são levantadas no chamado método assíncrono. Uma exceção que é gerada em um método que retorna um Task ou Task<TResult> é armazenado na tarefa retornada. Se você não aguardar a tarefa ou verificar explicitamente se há exceções, a exceção será perdida. Se você aguardar a tarefa, sua exceção será relançada.

Como prática recomendada, você deve sempre aguardar a chamada.

Você deve considerar suprimir o aviso somente se tiver certeza de que não deseja esperar a conclusão da chamada assíncrona e que o método chamado não gerará exceções. Nesse caso, você pode suprimir o aviso atribuindo o resultado da tarefa da chamada a uma variável.

O exemplo a seguir mostra como causar o aviso, como suprimi-lo e como aguardar a chamada.

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.");
}

No exemplo, se você escolher Chamada #1 ou Chamada #2, o método CalledMethodAsync assíncrono não esperado será concluído depois que o chamador CallingMethodAsync e o chamador do chamador forem concluídos. A última linha na saída a seguir mostra quando o método chamado termina. A entrada e saída do manipulador de eventos que chama CallingMethodAsync o exemplo completo são marcadas na saída.

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.

Você também pode suprimir avisos do compilador usando #pragma diretivas de aviso .

Exemplo

O aplicativo de console a seguir contém os métodos do exemplo anterior. As etapas a seguir configuram o aplicativo.

  1. Crie um aplicativo de console e nomeie-o AsyncWarningcomo .

  2. No Editor de Códigos do Visual Studio, escolha o arquivo Program.cs .

  3. Substitua o código no Program.cs pelo seguinte código.

    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.
    }
    
  4. Selecione a tecla F5 para executar o programa.

A saída esperada aparece no final do código.

Consulte também