Compartir a través de


Tipos de retorno asíncrono (Visual Basic)

Los métodos asincrónicos tienen tres tipos de valor devuelto posibles: Task<TResult>, Tasky void. En Visual Basic, el tipo de valor devuelto void se escribe como un procedimiento Sub. Para obtener más información sobre los métodos asincrónicos, vea Programación asincrónica con Async y Await (Visual Basic).

Cada tipo de valor devuelto se examina en una de las secciones siguientes y puede encontrar un ejemplo completo que use los tres tipos al final del tema.

Nota:

Para ejecutar el ejemplo, debe tener Visual Studio 2012 o versiones posteriores y .NET Framework 4.5 o posterior instalado en el equipo.

Tipo de valor devuelto Task(T)

El tipo de valor devuelto Task<TResult> se usa para un método asincrónico que contiene una instrucción Return en la que el operando tiene el tipo TResult.

En el ejemplo siguiente, el TaskOfT_MethodAsync método asincrónico contiene una instrucción return que devuelve un entero. Por lo tanto, la declaración de método debe especificar un tipo de valor devuelto de Task(Of Integer).

' 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

Cuando se llama a TaskOfT_MethodAsync desde una expresión await, esta recupera el valor entero (el valor de leisureHours) que está almacenado en la tarea que TaskOfT_MethodAsync devuelve. Para obtener más información sobre las expresiones await, vea Await Operator.

El siguiente código llama al método TaskOfT_MethodAsync y lo espera. El resultado se asigna a la result1 variable .

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

Puede comprender mejor cómo sucede esto separando la llamada a TaskOfT_MethodAsync de la aplicación de Await, como se muestra en el código siguiente. Una llamada al método TaskOfT_MethodAsync que no se espera inmediatamente devuelve Task(Of Integer), como se podría esperar de la declaración del método. La tarea se asigna a la variable integerTask en el ejemplo. Dado que integerTask es un Task<TResult>, contiene una propiedad Result de tipo TResult. En este caso, TResult representa un tipo entero. Cuando Await se aplica a integerTask, la expresión await se evalúa en el contenido de la propiedad Result de integerTask. El valor se asigna a la variable result2.

Advertencia

La propiedad Result es una propiedad de bloqueo. Si intenta acceder a ella antes de que finalice su tarea, el subproceso que está activo actualmente se bloquea hasta que se complete la tarea y el valor esté disponible. En la mayoría de los casos, se debe tener acceso al valor usando Await en lugar de tener acceso directamente a la propiedad.

' 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 &= "Application can continue working while the Task(Of T) runs. . . . " & vbCrLf

Dim result2 As Integer = Await integerTask

Las instrucciones display del código siguiente comprueban que los valores de la result1 variable, la result2 variable y la Result propiedad son los mismos. Recuerde que la propiedad Result es una propiedad bloqueo y no se debe tener acceso a ella antes de haber esperado a su tarea.

' Display the values of the result1 variable, the result2 variable, and
' the resultTask.Result property.
textBox1.Text &= vbCrLf & $"Value of result1 variable:   {result1}" & vbCrLf
textBox1.Text &= $"Value of result2 variable:   {result2}" & vbCrLf
textBox1.Text &= $"Value of resultTask.Result:  {integerTask.Result}" & vbCrLf

Tipo de valor devuelto Task

Los métodos asincrónicos que no contienen una instrucción return o que contienen una instrucción return que no devuelve un operando normalmente tienen un tipo de valor devuelto de Task. Estos métodos serían procedimientos Sub si se escribieran para ejecutarse sincrónicamente. Si se usa un tipo de valor devuelto Task para un método asincrónico, un método de llamada puede usar un operador Await para suspender la finalización del llamador hasta que finalice el método asincrónico llamado.

En el ejemplo siguiente, el método Task_MethodAsync asincrónico no contiene una instrucción return. Por lo tanto, se especifica un tipo de retorno Task para el método, lo que permite que Task_MethodAsync sea esperado. La definición del Task tipo no incluye una Result propiedad para almacenar un valor devuelto.

' 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 &= vbCrLf & "Sorry for the delay. . . ." & vbCrLf

    ' This method has no return statement, so its return type is Task.
End Function

Se llama y se espera a Task_MethodAsync mediante una instrucción await en lugar de una expresión await, similar a la instrucción de llamada para un método Sub sincrónico o que devuelve nulo. La aplicación de un Await operador en este caso no genera un valor.

El siguiente código llama al método Task_MethodAsync y lo espera.

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

Como en el ejemplo anterior Task<TResult>, puede separar la llamada a Task_MethodAsync de la aplicación de un operador Await, como muestra el código siguiente. Sin embargo, recuerde que un Task no tiene una propiedad Result y que no se genera ningún valor cuando se aplica un operador await a un Task.

El código siguiente separa la llamada de Task_MethodAsync de la espera de la tarea que Task_MethodAsync devuelve.

' 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 &= vbCrLf & "Application can continue working while the Task runs. . . ." & vbCrLf

Await simpleTask

Tipo de valor devuelto Void

El uso principal de los procedimientos Sub es en los controladores de eventos, donde no hay ningún tipo de valor devuelto (denominado tipo de valor devuelto void en otros lenguajes). También se puede usar una devolución void para invalidar los métodos que devuelven void o para los métodos que realizan actividades que se pueden clasificar como "fire and forget" (dispare y olvídese). Sin embargo, debe devolver Task siempre que sea posible, ya que no se puede esperar a un método asincrónico que devuelve void. Cualquier llamador de dicho método debe poder continuar hasta completar sin esperar a que finalice el método asincrónico llamado, y el llamador debe ser independiente de los valores o excepciones que genere el método asincrónico.

El llamador de un método asincrónico que devuelve void no puede detectar excepciones arrojadas desde el método, y es probable que estas excepciones no controladas provoquen un error en su aplicación. Si se produce una excepción en un método asincrónico que devuelve un Task o un Task<TResult>, la excepción se almacena en la tarea devuelta y se lanza de nuevo cuando se aguarda la tarea. Por tanto, asegúrese de que cualquier método asincrónico que puede producir una excepción tiene un tipo de valor devuelto de Task o Task<TResult> y que se esperan llamadas al método.

Para obtener más información sobre cómo detectar excepciones en métodos asincrónicos, vea Try... Catch... Finally Statement.

El código siguiente define un controlador de eventos asincrónico.

' 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

Ejemplo completo

El siguiente proyecto de Windows Presentation Foundation (WPF) contiene los ejemplos de código de este tema.

Para ejecutar el proyecto, realice los pasos siguientes:

  1. Inicie Visual Studio.

  2. En la barra de menús, elija Archivo, Nuevo, Proyecto.

    Se abre el cuadro de diálogo Nuevo proyecto .

  3. En la categoría Instalado, Plantillas , elija Visual Basic y, a continuación, elija Windows. Elija Aplicación WPF en la lista de tipos de proyecto.

  4. Escriba AsyncReturnTypes como nombre del proyecto y, a continuación, elija el botón Aceptar .

    El proyecto nuevo aparece en el Explorador de soluciones.

  5. En el Editor de código de Visual Studio, elija la pestaña MainWindow.xaml .

    Si la pestaña no está visible, abra el menú contextual de MainWindow.xaml en el Explorador de soluciones y, a continuación, elija Abrir.

  6. En la ventana XAML de MainWindow.xaml, reemplace el código por el código siguiente.

    <Window x:Class="MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://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>
    

    Una ventana simple que contiene un cuadro de texto y un botón aparece en la ventana Diseño de MainWindow.xaml.

  7. En el Explorador de soluciones, abra el menú contextual de MainWindow.xaml.vb y seleccione Ver código.

  8. Reemplace el código de MainWindow.xaml.vb por el código siguiente.

    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 &= "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 &= vbCrLf & $"Value of result1 variable:   {result1}" & vbCrLf
            textBox1.Text &= $"Value of result2 variable:   {result2}" & vbCrLf
            textBox1.Text &= $"Value of resultTask.Result:  {integerTask.Result}" & vbCrLf
    
            ' 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 &= 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 &= vbCrLf & "Sorry for the delay. . . ." & vbCrLf
    
            ' This method has no return statement, so its return type is Task.
        End Function
    
    End Class
    
  9. Presione la tecla F5 para ejecutar el programa y elija el botón Inicio .

    Debería aparecer la siguiente salida:

    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 también