编译器警告(等级 1)CS4014

由于此调用不会等待,因此在调用完成前将继续执行当前方法。请考虑将“await”运算符应用于调用结果。

当前方法调用返回 TaskTask<TResult>,不应用 等待 运算符应用于该结果的异步方法。 对异步方法的调用将启动异步任务。 但是,在中,因为 await 运算符不是应用的,程序将继续运行,而不等待任务完成。 在大多数情况下,此行为不是预期。 通常被调用的方法的其他方面依赖于调用的结果,或者最低限度上,调用方法预计完成,在从包含调用的方法之前返回。

同样重要的问题是发生在调用异步方法引发的异常。 在方法引发返回 TaskTask<TResult> 的异常在返回的任务存储。 如果不等待任务也不显式检查异常,则丢失。 如果您等待任务,其异常来重新引发。

作为一个最优方法,应始终等待调用。

应考虑禁止显示该警告,只有 + 当确保将不要等待异步调用完成,然后调用方法不会引发任何异常。 在这种情况,您可以通过分配调用的任务结果禁止显示该警告给变量。

下面的示例演示如何导致该警告,如何禁止它以及如何等待调用。

async Task CallingMethodAsync()
{
    resultsTextBox.Text += "\r\n  Entering calling method.";
    // Variable delay is used to slow down the called method so that you can
    // distinguish between awaiting and not awaiting in the program's output.
    // You can adjust the value to produce the output that this topic shows
    // after the code.
    var delay = 5000;

    // 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(delay);

    // 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(delay);

    // 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(delay);

    // If the call to CalledMethodAsync isn't awaited, CallingMethodAsync
    // continues to run and, in this example, finishes its work and returns
    // to its caller.
    resultsTextBox.Text += "\r\n  Returning from calling method.";
}


async Task CalledMethodAsync(int howLong)
{
    resultsTextBox.Text += 
        "\r\n    Entering called method, starting and awaiting Task.Delay.";

    // Slow the process down a little so that you can distinguish between
    // awaiting and not awaiting in the program's output. Adjust the value
    // for howLong if necessary.
    await Task.Delay(howLong);
    resultsTextBox.Text += 
        "\r\n    Task.Delay is finished--returning from called method.";
}

在此示例中,因此,如果选择调用 #1 或调用 #2,在其调用方 (CallingMethodAsync) 之后的 unawaited 异步方法 (CalledMethodAsync) 完成,并且调用方的调用方 (startButton_Click) 已完成。 当调用方法完成时,以下输出的最后一行显示您。 项以及从输出中对该完整示例中的 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(C# 参考) 指令,还可以禁止编译器警告。

示例

以下 windows 演示基础 (WPF) 应用程序包含前面示例中的方法。 以下步骤将的应用程序。

  1. 创建一个 WPF 应用程序,并将其命名为 AsyncWarning。

  2. 在 Visual Studio 代码编辑器"中,选择 MainWindow.xaml 选项。

    如果看不到选项卡,打开 MainWindow.xaml 的快捷菜单在 解决方案资源管理器,然后选择 查看代码

  3. 用下面的代码替换在 MainWindow.xaml XAML 视图中的代码。

    <Window x:Class="AsyncWarning.MainWindow"
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Button x:Name="startButton" Content="Start" HorizontalAlignment="Left" Margin="214,28,0,0" VerticalAlignment="Top" Width="75" HorizontalContentAlignment="Center" FontWeight="Bold" FontFamily="Aharoni" Click="startButton_Click" />
            <TextBox x:Name="resultsTextBox" Margin="0,80,0,0" TextWrapping="Wrap" FontFamily="Lucida Console"/>
        </Grid>
    </Window>
    

    包含一个按钮和文本框的简单窗口显示 MainWindow.xaml 设计 视图。

    有关 XAML 设计器的更多信息,请参见 使用 XAML 设计器创建 UI。 有关如何生成简单的 UI 的信息,请参见 演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)“创建 WPF 应用程序”和“设计简单的 WPF 的”部分。

  4. 用下面的代码替换在 MainWindow.xaml.cs 的代码。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace AsyncWarning
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private async void startButton_Click(object sender, RoutedEventArgs e)
            {
                resultsTextBox.Text += "\r\nEntering the Click event handler.";
                await CallingMethodAsync();
                resultsTextBox.Text += "\r\nExiting the Click event handler.";
            }
    
    
            async Task CallingMethodAsync()
            {
                resultsTextBox.Text += "\r\n  Entering calling method.";
                // Variable delay is used to slow down the called method so that you can
                // distinguish between awaiting and not awaiting in the program's output.
                // You can adjust the value to produce the output that this topic shows
                // after the code.
                var delay = 5000;
    
                // 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(delay);
    
                // 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(delay);
    
                // 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(delay);
    
                // If the call to CalledMethodAsync isn't awaited, CallingMethodAsync
                // continues to run and, in this example, finishes its work and returns
                // to its caller.
                resultsTextBox.Text += "\r\n  Returning from calling method.";
            }
    
    
            async Task CalledMethodAsync(int howLong)
            {
                resultsTextBox.Text += 
                    "\r\n    Entering called method, starting and awaiting Task.Delay.";
    
                // Slow the process down a little so that you can distinguish between
                // awaiting and not awaiting in the program's output. Adjust the value
                // for howLong if necessary.
                await Task.Delay(howLong);
                resultsTextBox.Text += 
                    "\r\n    Task.Delay is finished--returning from called method.";
            }
        }
    
        // Output with Call #1 or Call #2. (Wait for the last line to appear.)
    
        // 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.
    
    
        // Output with Call #3, which awaits the call to CalledMethodAsync.
    
        // Entering the Click event handler.
        //   Entering calling method.
        //     Entering called method, starting and awaiting Task.Delay.
        //     Task.Delay is finished--returning from called method.
        //   Returning from calling method.
        // Exiting the Click event handler.
    }
    
  5. 选择 F5 键运行程序,然后选择 启动 按钮。

    预期的输出显示在代码的结尾。

请参见

参考

await(C# 参考)

概念

使用 Async 和 Await 的异步编程(C# 和 Visual Basic)