使用 async 修饰符可将方法、lambda 表达式或匿名方法指定为异步。如果对方法或表达式使用此修饰符,则其称为异步方法。如下示例定义了一个名为 FF异步示例 的异步方法:

public async Task < int > FF异步示例 ( )
{
    //……
}

如下的代码常见于异步方法中,且使用 HttpClient . GetStringAsync 方法:

static readonly HttpClient client = new ( );
static async Task Main ( string [ ] args )
    {
        // 在 try / catch 块中调用异步网络方法来处理异常
        try
            {
                // using HttpResponseMessage response = await client . GetAsync ( "http://www.contoso.com/" );
                // response . EnsureSuccessStatusCode ( );
                // string responseBody = await response . Content . ReadAsStringAsync ( );
                // 上面的三行代码可以用下面的 new helper 方法代替
                string responseBody = await client . GetStringAsync ( "http://www.contoso.com/" );

                Console . WriteLine ( responseBody );
            }
        catch ( HttpRequestException e )
            {
                Console . WriteLine ( "\n异常!" );
                Console . WriteLine ( $"信息:{e . Message} " );
            }
    }

异步方法同步运行,直至到达其第一个 await 表达式,此时会将方法挂起,直到等待的任务完成。同时,如下节示例中所示,控件将返回到方法的调用方。

如果 async 关键字修改的方法不包含 await 表达式或语句,则该方法将同步执行。编译器警告(CS4014)将通知你不包含 await 语句的任何异步方法,因为该情况可能表示存在错误。

async 关键字是上下文关键字,原因在于只有当它修饰方法、lambda 表达式或匿名方法时,它才是关键字。在所有其他上下文中,都会将其解释为标识符。

示例

下面的示例展示了异步事件处理程序 annKS_Click 和异步方法 FFasyncInt 之间的控制结构和流程。此异步方法的结果是 Web 页面的字符数。此代码适用于在 Visual Studio 中创建的 Windows Presentation Foundation(WPF)应用或 Windows 应用商店应用;参见有关设置应用的代码注释。

可以在 Visual Studio 中将此代码作为 Windows Presentation Foundation(WPF)应用或 Windows 应用商店应用运行。需要一个名为 annKS 的 button 控件和一个名为 wbkJG 的 TextBlock 控件。切勿忘记设置名称和处理程序,以便获得类似于以下代码的内容:

    <Grid Margin="0,0,10,365">
        <Grid Margin="10,75,0,-355">
            <TextBlock x:Name="wbkJG" TextWrapping="Wrap"/>
        </Grid>
        <Button x:Name="annKS" Content="开始" Margin="10,0,0,0" Click="annKS_Click"/>

    </Grid>
  • 若为 WPF 应用程序:

    • 添加对 System . Net . Http 的引用
  • 若为 Windows 应用商店应用程序:

    • 添加对 System . Net . Http 和 System . Threading . Tasks 的引用
{
    public MainWindow()
        {
            InitializeComponent();
        }

    private async void annKS_Click ( object sender , RoutedEventArgs e )
        {
            wbkJG . Text = "";
            wbkJG . Text += "开始异步操作:\n";

            try
                {
                    int CD = await FFasyncInt ( );
                    // 请注意,您可以将 “await FFasyncInt ( )” 放在 “CD” 所在的下一行,但由于 ‘+=’ 获取 wbkJG 的值时,您不会看到 FFasyncInt 设置文本的全局副作用
                    wbkJG . Text += $"长度:{CD:N0}\n";
                }
            catch ( Exception ex )
                {
                    MessageBox . Show ( ex . Message );
                }
        }

    public async Task<int> FFasyncInt ( )
        {
            HttpClient KHD = new ( );
            int IntL = ( await KHD . GetStringAsync ( "http://msdn.microsoft.com" ) ) . Length;
            wbkJG. Text += "准备完成 FFasyncInt。\n";
            return IntL;
        }
    }

返回类型

异步方法可具有以下返回类型:

  • Task
  • Task < TResult >
  • void。对于除事件处理程序以外的代码,通常不鼓励使用 async void 方法,因为调用方不能 await 那些方法,并且必须实现不同的机制来报告成功完成或错误条件
  • 任何具有可访问的 GetAwaiter 方法的类型。System . Threading . Tasks . ValueTask < TResult > 类型属于此类实现。它通过添加 NuGet 包 System . Threading . Tasks . Extensions 的方式可用

此异步方法既不能声明任何 in、ref 或 out 参数,也不能具有引用返回值,但它可以调用具有此类参数的方法。

如果异步方法的返回语句指定一个 < TResult > 类型的操作数,则应指定 Task < TResult > 作为方法的返回类型。如果当方法完成时未返回有意义的值,则应使用 Task。 即对方法的调用将返回一个 Task,但是当 Task 完成时,任何等待 Task 的所有 await 表达式的计算结果都为 void。

你应主要使用 void 返回类型来定义事件处理程序,这些处理程序需要此返回类型。void 返回异步方法的调用方不能等待,并且无法捕获该方法引发的异常。

可以返回另一个类型(通常为值类型),该类型具有 GetAwaiter 方法,可最大程度减少代码段性能关键部分中的内存分配。


兔子码农
4 声望1 粉丝

一个酒晕子