Tipos de retorno assíncronos (C# e Visual Basic)

Os métodos Async têm três tipos de retorno possíveis: Task, Task e vácuo. No Visual Basic, o tipo de retorno nulo é escrito como um procedimento Sub . Para obter mais informações sobre métodos assíncronos, consulte Programação assíncrona com Async e Await (C# e Visual Basic).

Cada tipo de retorno é examinado em uma das seguintes seções, e você pode localizar um exemplo completo que usa todos os três tipos no final do tópico.

Dica

Para executar o exemplo, você deve ter o Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 for Windows Desktop, Visual Studio Express 2013 para Windows, ou o .NET Framework 4.5 ou 4.5.1 instalado no seu computador.

Este tópico contém as seções a seguir.

  • Tipo de retorno da tarefa(T)
  • Tipo de retorno da tarefa
  • Tipo de retorno void
  • Exemplo completo
  • Tópicos relacionados

Tipo de retorno da tarefa(T)

O tipo de retorno Task é usado para um método assíncrono que contém uma declaração Retorno (Visual Basic) ou retorno (C#) na qual o operando é do tipo TResult.

No exemplo a seguir, o método assíncrono TaskOfT_MethodAsync contém uma instrução de retorno que retorna um número inteiro. Portanto, a declaração de método deve especificar um tipo de retorno de Task(Of Integer) no Visual Basic ou de Task<int> no C#.

' 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;
}

Quando TaskOfT_MethodAsync é chamado de uma expressão de espera, a expressão de espera retorna o valor inteiro (o valor de leisureHours) que é armazenado na tarefa retornada por TaskOfT_MethodAsync. Para obter mais informações sobre expressões de espera, consulte Operador Await (Visual Basic) ou await (Referência de C#).

O código a seguir chama e espera o método TaskOfT_MethodAsync. O resultado é atribuído à variável 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();

Você pode entender melhor como isso acontece separando a chamada para TaskOfT_MethodAsync do aplicativo de Await ou de await, pois o código a seguir é exibido. Uma chamada para o método TaskOfT_MethodAsync que não é imediatamente esperado um Task(Of Integer) ou Task<int>, como você esperaria da declaração de método. A tarefa é atribuída à variável integerTask no exemplo. Como integerTask é um Task, contém uma propriedade Result de tipo TResult. Nesse caso, TResult representa um tipo inteiro. Quando Await ou await são aplicados a integerTask, a expressão de espera avalia o conteúdo da propriedade de Result de integerTask. O valor é atribuído à variável result2.

Aviso

A propriedade Result é uma propriedade de bloqueio.Se você tentar acessá-la antes que sua tarefa seja concluída, o thread atualmente ativo será bloqueado até que a tarefa seja concluída e que o valor esteja disponível.Na maioria dos casos, você deverá acessar o valor usando Await ou await em vez de acessar a propriedade diretamente.

' 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;

As instruções de exibição no código a seguir verificam se os valores da variável de result1 , da variável de result2 e a propriedade de Result são os mesmos. Lembre-se de que a propriedade de Result é uma propriedade de bloqueio e não deve ser acessada antes que a tarefa seja esperada.

' 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);

Tipo de retorno da tarefa

Os métodos Async que não contêm uma instrução return ou que contêm uma instrução return que não retorna um operando geralmente têm um tipo de retorno Task. Esses métodos seriam métodos de retorno nuloSub no Visual Basic) se fossem gravados para serem executado de forma síncrona. Se você usar um tipo de retorno Task para um método assíncrono, um método de chamada poderá usar um operador await para suspender a conclusão do chamador até que o método assíncrono chamado tenha terminado.

No exemplo a seguir, o método assíncrono Task_MethodAsync não contém uma instrução de retorno. Portanto, você especifica um tipo de retorno de Task para o método, que permite que Task_MethodAsync seja esperado. A definição de tipo de Task não inclui uma propriedade de Result para armazenar um valor de retorno.

' 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 é chamado e esperado usando uma instrução de espera, em vez de uma expressão de espera, semelhante à instrução de chamada para Sub ou método de retorno nulo. O aplicativo de um operador de espera, nesse caso, não produz um valor.

O código a seguir chama o método e espera 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();

Como no exemplo anterior Task, você pode separar a chamada a Task_MethodAsync do aplicativo de um operador de espera, conforme o código a seguir mostra. No entanto, lembre-se de que a Task não tem uma propriedade Result e nenhum valor é gerado quando um operador de espera é aplicado à Task.

O código a seguir separa a chamada de Task_MethodAsync aguardando a tarefa que Task_MethodAsync retorna.

' 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;

Tipo de retorno void

O uso primário do tipo de retorno vago (procedimentos de Sub no Visual Basic) está nos manipuladores de eventos, onde um tipo de retorno vago é necessário. Um retorno de void também pode ser usado para substituir métodos de retorno vagos ou para métodos que executam atividades que podem ser categorizadas como "faça e esqueça". No entanto, você deve retornar a Task sempre que possível, pois um método assíncrono de retorno nulo não pode ser esperado. Qualquer chamador desse método deve poder continuar sem esperar pelo método chamado assíncrono para concluir, e o chamador deve ser independente de quaisquer valores ou exceções que o método assíncrono gerar.

O chamador de um método assíncrono de retorno não nulo não pode capturar exceções que são geradas do método, e essas exceções não tratadas, provavelmente provocam falha no aplicativo. Se ocorrer uma exceção em um método assíncrono que retorna Task ou Task, a exceção será armazenada na tarefa retornada e lançada novamente quando a tarefa for esperada. Portanto, certifique-se de que qualquer método de async que possa gerar uma exceção tenha um tipo de retorno de Task ou de Task e que as chamadas para o método sejam esperadas.

Para obter mais informações sobre como capturar exceções nos métodos assíncronos, consulte try-catch (Referência de C#) ou Instrução Try...Catch...Finally (Visual Basic).

O código a seguir define um manipulador de eventos de async.

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

Exemplo completo

O seguinte projeto do Windows Presentation Foundation (WPF) contém os exemplos de código deste tópico.

Para executar o projeto, execute as seguintes etapas:

  1. Inicie o Visual Studio.

  2. Na barra de menu, escolha Arquivo, Novo, Projeto.

    A Caixa de diálogo Novo Projeto é exibida.

  3. Na categoria Instalado, Modelos, escolha Visual Basic ou Visual C#, e então escolha Windows. Escolha Aplicativo WPF na lista de tipos de projeto.

  4. Digite AsyncReturnTypes como o nome do projeto e clique no botão OK.

    O novo projeto aparece no Gerenciador de Soluções.

  5. No Editor de Códigos do Visual Studio, escolha a guia MainWindow.xaml.

    Se a guia não está visível, abra o menu de atalho de MainWindow.xaml no Gerenciador de Soluções e escolha Abrir.

  6. Na janela XAML de MainWindow.xaml, substitua o código pelo seguinte.

    <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>
    

    Uma janela simples que contém uma caixa de texto e um botão aparece na janela Design de MainWindow.xaml.

  7. Em Gerenciador de Soluções, abra o menu de atalho para MainWindow.xaml.vb ou MainWindow.xaml.cs e, em seguida, escolha Exibir Código.

  8. Substitua o código no MainWindow.xaml.vb ou MainWindow.xaml.cs com o código a seguir.

    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. Escolha a tecla F5 para executar o programa e escolha o botão Iniciar.

    As seguintes saídas devem aparecer.

    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.
    

Consulte também

Tarefas

Instruções passo a passo: acessando a Web e usando Async e Await (C# e Visual Basic)

Passo a passo: Usando o depurador com métodos assíncronos

Referência

async (Referência de C#)

Async (Visual Basic)

Operador Await (Visual Basic)

await (Referência de C#)

FromResult``1

Conceitos

Fluxo de controle em programas assíncronos (C# e Visual Basic)