Asynchrone Rückgabetypen (C# und Visual Basic)

Asynchrone Methoden haben drei mögliche Rückgabetypen: Task, Task und den void-Typ. In Visual Basic wird der void-Rückgabetyp als Sub-Prozedur geschrieben. Weitere Informationen über asynchrone Methoden finden Sie unter Asynchrone Programmierung mit Async und Await (C# und Visual Basic).

Jeder Rückgabetyp wird in einem der folgenden Abschnitte untersucht und am Ende des Themas wird ein vollständiges Beispiel alle drei Typen verwenden.

Hinweis

Zum Ausführen des Beispiels muss Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 für Windows Desktop Visual Studio Express 2013 für Windows oder .NET Framework 4.5 bzw. 4.5.1 auf dem Computer installiert sein.

Dieses Thema enthält folgende Abschnitte.

  • Task(T)-Rückgabetyp
  • Aufgabenrückgabetyp
  • Rückgabetyp "Void"
  • Vollständiges Beispiel
  • Verwandte Themen

Task(T)-Rückgabetyp

Der Task-Rückgabetyp wird für eine asynchrone Methode verwendet, die eine Return-Anweisung (Visual Basic) oder return-Anweisung (C#) enthält, in der der Operand den TResult-Typ hat.

Im folgenden Beispiel enthält die asynchrone TaskOfT_MethodAsync-Methode eine "return"-Anweisung, die eine ganze Zahl zurückgibt. Daher muss die Methodendeklaration einen Rückgabetyp Task(Of Integer) in Visual Basic oder Task<int> in C# angeben.

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

Wenn TaskOfT_MethodAsync aus einem "await"-Ausdruck aufgerufen wird, ruft der "await"-Ausdruck den ganzzahligen Wert ab (der Wert von leisureHours), der in der Aufgabe gespeichert wird, die von TaskOfT_MethodAsync zurückgegeben wird. Weitere Informationen zu "await"-Ausdrücken finden Sie unter Await-Operator (Visual Basic) oder await (C#-Referenz).

Der folgende Code ruft auf und erwartet die TaskOfT_MethodAsync-Methode. Das Ergebnis wird der result1-Variablen zugewiesen.

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

Sie können die Vorgehensweise besser verstehen, wenn Sie den Aufruf von TaskOfT_MethodAsync von der Anwendung von Await oder await trennen, wie der folgenden Code zeigt. Ein Aufruf der TaskOfT_MethodAsync-Methode, die nicht sofort eine Antwort erwartet, gibt ein Task(Of Integer) oder Task<int> zurück, wie Sie es von der Deklaration der Methode erwarten. Die Aufgabe wird im Beispiel der integerTask-Variablen zugewiesen. Da integerTask eine Task ist, enthält es eine Result-Eigenschaft des Typs TResult. In diesem Fall stellt TResult einen ganzzahligen Typ dar. Wenn Await oder await auf integerTask angewendet wird, wertet der "await"-Ausdruck den Inhalt der Result-Eigenschaft von integerTask aus. Der Wert wird der result2-Variablen zugewiesen.

Warnung

Die Result-Eigenschaft ist eine Blocking-Eigenschaft.Wenn Sie darauf zuzugreifen versuchen, bevor seine Aufgabe beendet ist, wird der momentan aktive Thread blockiert, bis die Aufgabe abgeschlossen und der Wert verfügbar ist.In den meisten Fällen sollten Sie auf den Wert zugreifen, indem Sie Await oder await verwenden, anstatt direkt auf die Eigenschaft zuzugreifen.

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

Die Anzeigeanweisungen im folgenden Code überprüfen, dass die Werte der result1-Variable, der result2-Variable und der Result-Eigenschaft gleich sind. Beachten Sie, dass die Result-Eigenschaft eine Blocking-Eigenschaft ist und nicht darauf zugegriffen werden sollte, bevor die Aufgabe abgeschlossen wurde.

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

Aufgabenrückgabetyp

Asynchrone Methoden, die keine "return"-Anweisung enthalten oder eine "return"-Anweisung enthalten, die keinen Operanden zurückgibt, haben normalerweise einen Rückgabetyp von Task. Solche Methoden würden "void" als Rückgabewert liefern (Sub-Prozeduren in Visual Basic), wenn sie für eine synchrone Ausführung geschrieben wurden. Wenn Sie einen Task-Rückgabetyp für eine asynchrone Methode verwenden, kann ein aufrufende Methode einen Erwartungsoperator verwenden, um den Abschluss des Aufrufers anzuhalten, bis die aufgerufene asynchrone Methode beendet ist.

Im folgenden Beispiel enthält die asynchrone Task_MethodAsync-Methode keine "return"-Anweisung. Daher geben Sie einen Task-Rückgabetyp für die Methode an, die Task_MethodAsync ein Warten ermöglicht. Die Definition des Task-Typs enthält keine Result-Eigenschaft, um einen Rückgabewert zu speichern.

' 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 wird aufgerufen und erwartet, indem eine "await"-Anweisung anstelle eines "await"-Ausdrucks verwendet wird, ähnlich der Aufrufanweisung für ein synchrones Sub oder eine Methode, die "void" zurückgibt. Die Anwendung eines Erwartungsoperators erzeugt in diesem Fall keinen Wert.

Der folgende Code ruft auf und erwartet die Task_MethodAsync-Methode.

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

Wie im vorherigen Beispiel Task können Sie den Aufruf von Task_MethodAsync mit einem Erwartungsoperator trennen, wie der folgende Code zeigt. Beachten Sie jedoch, dass Task über keine Result-Eigenschaft verfügt und dass kein Wert erzeugt wird, wenn ein Erwartungsoperator auf Task angewendet wird.

Der folgende Code trennt Aufrufe von Task_MethodAsync vom Erwarten der Aufgabe, die Task_MethodAsync zurückgibt.

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

Rückgabetyp "Void"

Der Hauptverwendungszweck des "void"-Rückgabetyps (Sub-Prozeduren in Visual Basic) liegt in den Ereignishandlern, für die ein "void"-Rückgabetyp erforderlich ist. Eine "void"-Rückgabe kann auch verwendet werden, um Methoden mit einer "void"-Rückgabe zu überschreiben, oder auch für Methoden, die "Fire-and-Forget"-Aktivitäten ausführen. Sie sollten nach Möglichkeit immer eine Task zurückgeben, da eine "void" zurückgebende asynchrone Methode nicht erwartet werden kann. Jeder Aufrufer einer solchen Methode muss in der Lage sein, in seiner Ausführung bis zum Abschluss fortzufahren, ohne auf die aufgerufene asynchrone Methode zu warten, und der Aufrufer muss unabhängig von den Werten oder Ausnahmen sein, die die asynchrone Methode generiert.

Der Aufrufer einer "void" zurückgebenden asynchronen Methode kann die von der Methode ausgelöste Ausnahmen nicht behandeln, und solche Ausnahmefehler können möglicherweise zu Fehlern in der Anwendung führen. Wenn eine Ausnahme in einer asynchronen Methode auftritt, die Task oder Task zurückgibt, wird die Ausnahme in der zurückgegebenen Aufgabe gespeichert und erneut ausgelöst, wenn die Aufgabe erwartet wird. Daher stellen Sie sicher, dass jede asynchrone Methode, die eine Ausnahme erstellen kann, über einen Rückgabetyp Task oder Task verfügt und die Aufrufe der Methode erwartet werden.

Weitere Informationen zum Auffangen von Ausnahmen in Async-Methoden finden Sie unter try-catch (C#-Referenz) oder Try...Catch...Finally-Anweisung (Visual Basic).

Der folgende Code definiert einen asynchrone Ereignishandler.

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

Vollständiges Beispiel

Das nächste Windows Presentation Foundation (WPF)-Projekt enthält die Codebeispiele aus diesem Thema.

Um das Projekt auszuführen, führen Sie die folgenden Schritte aus:

  1. Starten Sie Visual Studio.

  2. Wählen Sie in der Menüleiste Datei, Neu, Projekt aus.

    Das Dialogfeld Neues Projekt wird angezeigt.

  3. Wählen Sie in Installiert die Kategorie Vorlagen aus, wählen Sie Visual Basic oder Visual C#, und dann Windows aus. Wählen Sie in der Liste der Projekttypen die WPF-Anwendung aus.

  4. Geben Sie AsyncReturnTypes als Name für das Projekt ein, und wählen Sie dann die Schaltfläche OK aus.

    Das neue Projekt wird im Projektmappen-Explorer angezeigt.

  5. Wählen Sie im Visual Studio Code Editor die Registerkarte MainWindow.xaml aus.

    Wenn die Registerkarte nicht sichtbar ist, öffnen Sie das Kontextmenü für "MainWindow.xaml" im Projektmappen-Explorer und wählen dann Öffnen aus.

  6. Ersetzen Sie den Code im Fenster XAML durch den folgenden Code.

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

    Ein einfaches Fenster mit einem Textfeld und einer Schaltfläche wird im Fenster Entwurf von "MainWindow.xaml" angezeigt.

  7. Öffnen Sie im Projektmappen-Explorer das Kontextmenü für "MainWindow.xaml.cs" oder "MainWindow.xaml.vb", und wählen Sie dann Code anzeigen aus.

  8. Ersetzen Sie den Code in "MainWindow.xaml.vb" bzw. "MainWindow.xaml.cs" durch den folgenden Code.

    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. Drücken Sie die Taste F5, um das Programm auszuführen, und klicken Sie dann auf die Schaltfläche Starten.

    Es sollte folgende Ausgabe angezeigt werden.

    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.
    

Siehe auch

Aufgaben

Exemplarische Vorgehensweise: Zugreifen auf das Web mit Async und Await (C# und Visual Basic)

Exemplarische Vorgehensweise: Verwenden des Debuggers mit Async-Methoden

Referenz

async (C#-Referenz)

Async (Visual Basic)

Await-Operator (Visual Basic)

await (C#-Referenz)

FromResult``1

Konzepte

Ablaufsteuerung in asynchronen Programmen (C# und Visual Basic)