Поделиться через


Предупреждение компилятора (уровень 1) CS4014

Так как этот вызов не ожидается, выполнение существующего метода продолжается до тех пор, пока вызов не будет завершен. Рассмотрите возможность применения оператора await к результату вызова.

Текущий метод вызывает асинхронный метод, который возвращает класс Task или Task<TResult> и не применяет оператор await к результату. Вызов асинхронного метода запускает асинхронную задачу. Однако поскольку оператор await не применяется, программа продолжает выполнение, не ожидая завершения задачи. Обычно разработчику требуется другое поведение. Обычно другие аспекты вызывающего метода зависят от результатов вызова или, как минимум, вызывающий метод должен завершиться до возврата из метода, который содержит вызов.

Также важной проблемой является обработка исключений, возникающих в вызываемом асинхронном методе. Исключение, которое возникает в методе, который возвращает Task или Task<TResult> хранится в возвращаемой задаче. Если не ожидать задачу или явно не проверять исключения, исключение будет потеряно. Если ожидать задачу, ее исключение будет создано повторно.

Рекомендуется всегда ожидать вызов.

Рекомендуется отключать предупреждение, только если вы уверены, что не нужно ожидать завершения асинхронного вызова и что вызванный метод не создаст исключения. В этом случае можно отключить предупреждение, присвоив переменной результат вызова задачи.

В следующем примере показано, как вызвать предупреждение, как отключить его и как ожидать вызов.

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

В этом примере при выборе Call #1 или Call #2, неожидаемый асинхронный метод CalledMethodAsync завершается после того, как завершатся вызвавший его метод CallingMethodAsync и метод, вызвавший этот метод. Последняя строка в следующем выводе показывает, когда завершается вызванный метод. Вход и выход из обработчика событий, который вызывает CallingMethodAsync , в полном примере помечены в выводе.

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.

Можно также отключить предупреждения компилятора с помощью директив #pragma warning.

Пример

Следующее консольное приложение содержит методы из предыдущего примера. Ниже описана настройка приложения.

  1. Создайте новое консольное приложение и присвойте ему имя AsyncWarning.

  2. В редакторе Visual Studio Code выберите файл Program.cs.

  3. Замените код файла Program.cs на код, приведенный ниже.

    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. Нажмите клавишу F5, чтобы запустить программу.

Ожидаемый результат отобразится в конце кода.

См. также