异步返回类型(C# 和 Visual Basic)

异步方法有三种可能的返回类型:TaskTask 和无效。 在 Visual Basic 中,void 返回类型编写为Sub过程。 有关异步方法的更多信息,请参见 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)

在以下节中之一检查每个返回类型,您可在主题末尾找到使用所有三种类型的完整示例。

备注

要运行此示例,必须在你的计算机上安装 Visual Studio 2012、Visual Studio 2013、Visual Studio Express 2012 for Windows Desktop、Visual Studio Express 2013 for Windows 或 .NET Framework 4.5 或 4.5.1。

本主题包括下列各节。

  • Task(T) 返回类型
  • 任务返回类型
  • 返回类型为 void
  • 完整的示例
  • 相关主题

Task(T) 返回类型

Task 返回类型用于包含其操作数拥有类型 TResult 的 Return (Visual Basic) 或者 return (C#) 语句的同步方法。

在下面的示例中,TaskOfT_MethodAsync 异步方法包含返回整数的返回语句。 因此,方法声明必须指定 Visual Basic 的 Task(Of Integer) 返回类型,或 C# 的 Task<int> 返回类型。

' TASK(OF T) EXAMPLE
Async Function TaskOfT_MethodAsync() As Task(Of Integer)

    ' The body of an async method is expected to contain an awaited  
    ' asynchronous call. 
    ' Task.FromResult is a placeholder for actual work that returns a string. 
    Dim today As String = Await Task.FromResult(Of String)(DateTime.Now.DayOfWeek.ToString())

    ' The method then can process the result in some way. 
    Dim leisureHours As Integer 
    If today.First() = "S" Then
        leisureHours = 16
    Else
        leisureHours = 5
    End If 

    ' Because the return statement specifies an operand of type Integer, the  
    ' method must have a return type of Task(Of Integer).  
    Return leisureHours
End Function
// TASK<T> EXAMPLE
async Task<int> TaskOfT_MethodAsync()
{
    // The body of the method is expected to contain an awaited asynchronous 
    // call. 
    // Task.FromResult is a placeholder for actual work that returns a string. 
    var today = await Task.FromResult<string>(DateTime.Now.DayOfWeek.ToString());

    // The method then can process the result in some way. 
    int leisureHours;
    if (today.First() == 'S')
        leisureHours = 16;
    else
        leisureHours = 5;

    // Because the return statement specifies an operand of type int, the 
    // method must have a return type of Task<int>. 
    return leisureHours;
}

如果 TaskOfT_MethodAsync 是从 await 表达式内调用的,await 表达式就会检索存储在任务中由 TaskOfT_MethodAsync 返回的整数值(leisureHours 的值)。 有关 await 表达式的更多信息,请参见 Await 运算符 (Visual Basic)await(C# 参考)

下面的代码调用并等待 TaskOfT_MethodAsync 方法。 该结果已赋给 result1 变量。

' Call and await the Task(Of T)-returning async method in the same statement. 
Dim result1 As Integer = Await TaskOfT_MethodAsync()
// Call and await the Task<T>-returning async method in the same statement. 
int result1 = await TaskOfT_MethodAsync();

您可以通过将调用分隔到来自 Await 或 await 应用程序的 TaskOfT_MethodAsync 来更好地了解这是如何发生的,如以下代码所示。 调用不立即等待的 TaskOfT_MethodAsync 方法将返回 Task(Of Integer) 或 Task<int>,如同您从方法的声明可预知的那样。 在该示例中,该任务分配给 integerTask 变量。 由于 integerTask 是 Task,其包含 Result 属性(类型为 TResult)。 在这种情况下,TResult 表示整数类型。 如果 Await 或 await 适用于 integerTask,await 表达式的计算结果为 integerTask 的 Result 属性的内容。 值已赋给 result2 变量。

警告

Result 属性是一个阻止属性。如果您尝试在它的任务完成之前对其进行访问,则当前处于活动状态的线程被阻止,直至任务完成和值可用。在大多数情况下,您应使用 Await 或 await 来访问值而不是直接访问属性。

' Call and await in separate statements. 
Dim integerTask As Task(Of Integer) = TaskOfT_MethodAsync()

' You can do other work that does not rely on resultTask before awaiting.
textBox1.Text &= String.Format("Application can continue working while the Task(Of T) runs. . . . " & vbCrLf)

Dim result2 As Integer = Await integerTask
// Call and await in separate statements.
Task<int> integerTask = TaskOfT_MethodAsync();

// You can do other work that does not rely on integerTask before awaiting.
textBox1.Text += String.Format("Application can continue working while the Task<T> runs. . . . \r\n");

int result2 = await integerTask;

下面的代码中的显示语句验证了 result1 变量、result2 变量和 Result 属性的值是相同的。 请记住,Result 属性是一个阻止属性,并且不得在任务等待之前进行访问。

' Display the values of the result1 variable, the result2 variable, and 
' the resultTask.Result property.
textBox1.Text &= String.Format(vbCrLf & "Value of result1 variable:   {0}" & vbCrLf, result1)
textBox1.Text &= String.Format("Value of result2 variable:   {0}" & vbCrLf, result2)
textBox1.Text &= String.Format("Value of resultTask.Result:  {0}" & vbCrLf, integerTask.Result)
// Display the values of the result1 variable, the result2 variable, and 
// the integerTask.Result property.
textBox1.Text += String.Format("\r\nValue of result1 variable:   {0}\r\n", result1);
textBox1.Text += String.Format("Value of result2 variable:   {0}\r\n", result2);
textBox1.Text += String.Format("Value of integerTask.Result: {0}\r\n", integerTask.Result);

任务返回类型

不包含 Return 语句或包含 Return 语句且不包含操作数的异步方法通常具有 Task 的返回类型。 如果将此类方法编写为同步运行,则其将成为无效的返回方法(Visual Basic 中的 Sub 过程)。 如果您对异步方法使用 Task 返回类型,则调用方法可以使用等待运算符挂起调用方的完成,直到调用异步方法完成。

在下面的示例中,异步方法 Task_MethodAsync 不包含返回语句。 因此,你为方法指定 Task 的返回类型,使得 Task_MethodAsync 被等待。 Task 类型的定义不包括一个存储返回值的 Result 属性。

' TASK EXAMPLE
Async Function Task_MethodAsync() As Task

    ' The body of an async method is expected to contain an awaited  
    ' asynchronous call. 
    ' Task.Delay is a placeholder for actual work.
    Await Task.Delay(2000)
    textBox1.Text &= String.Format(vbCrLf & "Sorry for the delay. . . ." & vbCrLf)

    ' This method has no return statement, so its return type is Task.  
End Function
// TASK EXAMPLE
async Task Task_MethodAsync()
{
    // The body of an async method is expected to contain an awaited  
    // asynchronous call. 
    // Task.Delay is a placeholder for actual work.
    await Task.Delay(2000);
    // Task.Delay delays the following line by two seconds.
    textBox1.Text += String.Format("\r\nSorry for the delay. . . .\r\n");

    // This method has no return statement, so its return type is Task.  
}

通过使用等待语句而不是等待表达式调用并等待 Task_MethodAsync,与同步 Sub 或无效返回方法的调用语句相似。 等待运算符的应用程序在这种情况下不生成值。

下面的代码调用并等待 Task_MethodAsync 方法。

' Call and await the Task-returning async method in the same statement.
Await Task_MethodAsync()
// Call and await the Task-returning async method in the same statement.
await Task_MethodAsync();

正如之前的 Task 示例,您可将针对 Task_MethodAsync 的调用从 await 操作符的应用程序分离,正如以下代码所示。 但请记住,Task 不具有 Result 属性,因此,当等待运算符应用于 Task 时不会生成任何值。

下面的代码将调用 Task_MethodAsync 与等待 Task_MethodAsync 返回的任务分离。

' Call and await in separate statements. 
Dim simpleTask As Task = Task_MethodAsync()

' You can do other work that does not rely on simpleTask before awaiting.
textBox1.Text &= String.Format(vbCrLf & "Application can continue working while the Task runs. . . ." & vbCrLf)

Await simpleTask
// Call and await in separate statements.
Task simpleTask = Task_MethodAsync();

// You can do other work that does not rely on simpleTask before awaiting.
textBox1.Text += String.Format("\r\nApplication can continue working while the Task runs. . . .\r\n");

await simpleTask;

返回类型为 void

Void 返回类型(Visual Basic 中的 Sub 程序)的主要用途在需要 void 返回类型的事件处理程序中。 Void 返回还可用于重写 void 返回方法或者用于执行可分类为“发后不理”的活动的方法。但是,您必须在可能的情况下返回一个 Task,因为不能等待无效返回异步方法。 此类方法的所有调用方必须能够继续完成,而不用等待调用异步方法完成,并且调用方必须不依赖于异步方法生成任何值或异常。

无效返回异步方法的调用方无法捕获该方法引发的异常,这种未经处理的异常很可能会导致应用程序失败。 如果返回 TaskTask 的异步方法中出现异常,则在任务等待时将此异常存储在返回的任务中并再次引发。 因此,请确保能够产生异常的任何异步方法均有 TaskTask 的返回类型,并确保方法的调用是所等待的调用。

有关如何在异步方法中捕捉异常的更多信息,请参见 try-catch(C# 参考)Try...Catch...Finally 语句 (Visual Basic)

下面的代码定义异步事件处理程序。

' SUB EXAMPLE
Async Sub button1_Click(sender As Object, e As RoutedEventArgs) Handles button1.Click

    textBox1.Clear()

    ' Start the process and await its completion. DriverAsync is a  
    ' Task-returning async method.
    Await DriverAsync()

    ' Say goodbye.
    textBox1.Text &= vbCrLf & "All done, exiting button-click event handler." 
End Sub
// VOID EXAMPLE 
private async void button1_Click(object sender, RoutedEventArgs e)
{
    textBox1.Clear();

    // Start the process and await its completion. DriverAsync is a  
    // Task-returning async method.
    await DriverAsync();

    // Say goodbye.
    textBox1.Text += "\r\nAll done, exiting button-click event handler.";
}

完整的示例

下面 Windows Presentation Foundation (WPF) 项目包含此主题中的代码示例。

若要运行此程序,请执行以下步骤:

  1. 启动 Visual Studio。

  2. 在菜单栏上,选择**“文件”“新建**、“项目”

    将打开**“新建项目”**对话框。

  3. 在“已安装应用程序”的“模板”类别中,选择“Visual Basic”或“Visual C#”,然后选择“Windows”。 从项目模板列表中,选择“WPF 应用程序”。

  4. 输入 AsyncReturnTypes作为项目名称,然后选择“确定”按钮。

    新项目出现在**“解决方案资源管理器”**中。

  5. 在 Visual Studio 代码编辑器中,选择“MainWindow.xaml”选项卡。

    如果此选项卡不可视,则在“解决方案资源管理器”中,打开 MainWindow.xaml 的快捷菜单,然后选择“打开”。

  6. 在 MainWindow.xaml 的“XAML”窗口中,使用下面的代码替换代码。

    <Window x:Class="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="button1" Content="Start" HorizontalAlignment="Left" Margin="214,28,0,0" VerticalAlignment="Top" Width="75" HorizontalContentAlignment="Center" FontWeight="Bold" FontFamily="Aharoni" Click="button1_Click"/>
            <TextBox x:Name="textBox1" Margin="0,80,0,0" TextWrapping="Wrap" FontFamily="Lucida Console"/>
    
        </Grid>
    </Window>
    
    <Window x:Class="AsyncReturnTypes.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="button1" Content="Start" HorizontalAlignment="Left" Margin="214,28,0,0" VerticalAlignment="Top" Width="75" HorizontalContentAlignment="Center" FontWeight="Bold" FontFamily="Aharoni" Click="button1_Click"/>
            <TextBox x:Name="textBox1" Margin="0,80,0,0" TextWrapping="Wrap" FontFamily="Lucida Console"/>
    
        </Grid>
    </Window>
    

    包含文本框和按钮的简单窗口显示在 MainWindow.xaml 的“设计”窗口中。

  7. 在“解决方案资源管理器”中,打开“MainWindow.xaml.vb”或“MainWindow.xaml.cs”的快捷菜单,然后选择“查看代码”。

  8. 将 MainWindow.xaml.vb 或 MainWindow.xaml.cs 中的代码替换为以下代码。

    Class MainWindow
    
        ' SUB EXAMPLE
        Async Sub button1_Click(sender As Object, e As RoutedEventArgs) Handles button1.Click
    
            textBox1.Clear()
    
            ' Start the process and await its completion. DriverAsync is a  
            ' Task-returning async method.
            Await DriverAsync()
    
            ' Say goodbye.
            textBox1.Text &= vbCrLf & "All done, exiting button-click event handler." 
        End Sub
    
    
        Async Function DriverAsync() As Task
    
            ' Task(Of T)  
            ' Call and await the Task(Of T)-returning async method in the same statement. 
            Dim result1 As Integer = Await TaskOfT_MethodAsync()
    
            ' Call and await in separate statements. 
            Dim integerTask As Task(Of Integer) = TaskOfT_MethodAsync()
    
            ' You can do other work that does not rely on resultTask before awaiting.
            textBox1.Text &= String.Format("Application can continue working while the Task(Of T) runs. . . . " & vbCrLf)
    
            Dim result2 As Integer = Await integerTask
    
            ' Display the values of the result1 variable, the result2 variable, and 
            ' the resultTask.Result property.
            textBox1.Text &= String.Format(vbCrLf & "Value of result1 variable:   {0}" & vbCrLf, result1)
            textBox1.Text &= String.Format("Value of result2 variable:   {0}" & vbCrLf, result2)
            textBox1.Text &= String.Format("Value of resultTask.Result:  {0}" & vbCrLf, integerTask.Result)
    
            ' Task  
            ' Call and await the Task-returning async method in the same statement.
            Await Task_MethodAsync()
    
            ' Call and await in separate statements. 
            Dim simpleTask As Task = Task_MethodAsync()
    
            ' You can do other work that does not rely on simpleTask before awaiting.
            textBox1.Text &= String.Format(vbCrLf & "Application can continue working while the Task runs. . . ." & vbCrLf)
    
            Await simpleTask
        End Function 
    
    
        ' TASK(OF T) EXAMPLE
        Async Function TaskOfT_MethodAsync() As Task(Of Integer)
    
            ' The body of an async method is expected to contain an awaited  
            ' asynchronous call. 
            ' Task.FromResult is a placeholder for actual work that returns a string. 
            Dim today As String = Await Task.FromResult(Of String)(DateTime.Now.DayOfWeek.ToString())
    
            ' The method then can process the result in some way. 
            Dim leisureHours As Integer 
            If today.First() = "S" Then
                leisureHours = 16
            Else
                leisureHours = 5
            End If 
    
            ' Because the return statement specifies an operand of type Integer, the  
            ' method must have a return type of Task(Of Integer).  
            Return leisureHours
        End Function 
    
    
        ' TASK EXAMPLE
        Async Function Task_MethodAsync() As Task
    
            ' The body of an async method is expected to contain an awaited  
            ' asynchronous call. 
            ' Task.Delay is a placeholder for actual work.
            Await Task.Delay(2000)
            textBox1.Text &= String.Format(vbCrLf & "Sorry for the delay. . . ." & vbCrLf)
    
            ' This method has no return statement, so its return type is Task.  
        End Function 
    
    End Class
    
    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 AsyncReturnTypes
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            // VOID EXAMPLE 
            private async void button1_Click(object sender, RoutedEventArgs e)
            {
                textBox1.Clear();
    
                // Start the process and await its completion. DriverAsync is a  
                // Task-returning async method.
                await DriverAsync();
    
                // Say goodbye.
                textBox1.Text += "\r\nAll done, exiting button-click event handler.";
            }
    
            async Task DriverAsync()
            {
                // Task<T>  
                // Call and await the Task<T>-returning async method in the same statement. 
                int result1 = await TaskOfT_MethodAsync();
    
                // Call and await in separate statements.
                Task<int> integerTask = TaskOfT_MethodAsync();
    
                // You can do other work that does not rely on integerTask before awaiting.
                textBox1.Text += String.Format("Application can continue working while the Task<T> runs. . . . \r\n");
    
                int result2 = await integerTask;
    
                // Display the values of the result1 variable, the result2 variable, and 
                // the integerTask.Result property.
                textBox1.Text += String.Format("\r\nValue of result1 variable:   {0}\r\n", result1);
                textBox1.Text += String.Format("Value of result2 variable:   {0}\r\n", result2);
                textBox1.Text += String.Format("Value of integerTask.Result: {0}\r\n", integerTask.Result);
    
                // Task 
                // Call and await the Task-returning async method in the same statement.
                await Task_MethodAsync();
    
                // Call and await in separate statements.
                Task simpleTask = Task_MethodAsync();
    
                // You can do other work that does not rely on simpleTask before awaiting.
                textBox1.Text += String.Format("\r\nApplication can continue working while the Task runs. . . .\r\n");
    
                await simpleTask;
            }
    
            // TASK<T> EXAMPLE
            async Task<int> TaskOfT_MethodAsync()
            {
                // The body of the method is expected to contain an awaited asynchronous 
                // call. 
                // Task.FromResult is a placeholder for actual work that returns a string. 
                var today = await Task.FromResult<string>(DateTime.Now.DayOfWeek.ToString());
    
                // The method then can process the result in some way. 
                int leisureHours;
                if (today.First() == 'S')
                    leisureHours = 16;
                else
                    leisureHours = 5;
    
                // Because the return statement specifies an operand of type int, the 
                // method must have a return type of Task<int>. 
                return leisureHours;
            }
    
    
            // TASK EXAMPLE
            async Task Task_MethodAsync()
            {
                // The body of an async method is expected to contain an awaited  
                // asynchronous call. 
                // Task.Delay is a placeholder for actual work.
                await Task.Delay(2000);
                // Task.Delay delays the following line by two seconds.
                textBox1.Text += String.Format("\r\nSorry for the delay. . . .\r\n");
    
                // This method has no return statement, so its return type is Task.  
            }
        }
    }
    
  9. 选择 F5 键运行程序,然后选择“开始”按钮。

    应显示下面的输出:

    Application can continue working while the Task<T> runs. . . . 
    
    Value of result1 variable:   5
    Value of result2 variable:   5
    Value of integerTask.Result: 5
    
    Sorry for the delay. . . .
    
    Application can continue working while the Task runs. . . .
    
    Sorry for the delay. . . .
    
    All done, exiting button-click event handler.
    

请参见

任务

演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)

演练:将调试器与异步方法一起使用

参考

async(C# 参考)

Async (Visual Basic)

Await 运算符 (Visual Basic)

await(C# 参考)

FromResult``1

概念

异步程序中的控制流(C# 和 Visual Basic)