Operator „await“: asynchron warten, bis eine Aufgabe abgeschlossen ist

Der Operator await hält die Auswertung der einschließenden async-Methode an, bis der asynchrone Vorgang abgeschlossen ist, der durch seinen Operanden dargestellt wird. Sobald der asynchrone Vorgang abgeschlossen ist, gibt der Operator await ggf. das Ergebnis des Vorgangs zurück. Wenn der Operator await auf den Operanden angewendet wird, der einen bereits abgeschlossenen Vorgang darstellt, wird das Ergebnis des Vorgangs sofort zurückgegeben, ohne dass die einschließende Methode angehalten wird. Der Operator await blockiert nicht den Thread, der die Async-Methode auswertet. Wenn der Operator await die einschließende asynchrone Methode anhält, wird das Steuerelement an den Aufrufer der Methode zurückgegeben.

Im folgenden Beispiel gibt die Methode HttpClient.GetByteArrayAsync die Instanz Task<byte[]> zurück, die einen asynchronen Vorgang darstellt, der ein Bytearray erzeugt, wenn er abgeschlossen wird. Der Operator await hält so lange die Methode DownloadDocsMainPageAsync an, bis der Vorgang abgeschlossen ist. Wenn DownloadDocsMainPageAsync angehalten wird, wird die Steuerung an die Methode Main zurückgegeben. Bei dieser handelt es sich um den Aufrufer von DownloadDocsMainPageAsync. Die Methode Main wird so lange ausgeführt, bis sie das Ergebnis des asynchronen Vorgangs benötigt, der von der Methode DownloadDocsMainPageAsync ausgeführt wird. Wenn GetByteArrayAsync alle Bytes abruft, wird der Rest der Methode DownloadDocsMainPageAsync ausgewertet. Danach wird der Rest der Methode Main ausgewertet.

public class AwaitOperator
{
    public static async Task Main()
    {
        Task<int> downloading = DownloadDocsMainPageAsync();
        Console.WriteLine($"{nameof(Main)}: Launched downloading.");

        int bytesLoaded = await downloading;
        Console.WriteLine($"{nameof(Main)}: Downloaded {bytesLoaded} bytes.");
    }

    private static async Task<int> DownloadDocsMainPageAsync()
    {
        Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading.");

        var client = new HttpClient();
        byte[] content = await client.GetByteArrayAsync("https://learn.microsoft.com/en-us/");

        Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading.");
        return content.Length;
    }
}
// Output similar to:
// DownloadDocsMainPageAsync: About to start downloading.
// Main: Launched downloading.
// DownloadDocsMainPageAsync: Finished downloading.
// Main: Downloaded 27700 bytes.

Der Operand eines await-Ausdrucks muss eine Benachrichtigung bereitstellen, wenn eine Aufgabe abgeschlossen ist. Im Allgemeinen wird eine Stellvertretung aufgerufen, wenn die Aufgabe abgeschlossen wird, entweder erfolgreich oder erfolglos. Der await-Abschnitt der C#-Sprachspezifikation enthält die Details zur Implementierung dieser Benachrichtigungen.

Im vorherigen Beispiel wird die async-Main-Methode verwendet. Weitere Informationen finden Sie im Abschnitt Der Operator „await“ in der Methode „Main“.

Hinweis

Eine Einführung in die asynchrone Programmierung finden Sie unter Asynchrone Programmierung mit „async“ und „await“. Die asynchrone Programmierung mit async und await folgt dem aufgabenbasierten asynchronen Muster.

Der Operator await kann nur in einer Methode, einem Lambdaausdruck oder einer anonymen Methode verwendet werden, die von dem Schlüsselwort async geändert wird. Innerhalb einer Async-Methode können Sie den Operator await nicht im Text einer synchronen Funktion, innerhalb des Blocks einer Lock-Anweisung oder in einem unsicheren Kontext verwenden.

Der Operand des Operators await gehört normalerweise einem der folgenden .NET-Typen an: Task, Task<TResult>, ValueTask oder ValueTask<TResult>. Allerdings kann es sich bei jedem Awaitable-Ausdruck um den Operanden des Operators await handeln. Weitere Informationen finden Sie im Abschnitt Awaitable-Ausdrücke der C#-Sprachspezifikation.

Der Ausdruck await t ist vom Typ TResult, wenn der Ausdruck t vom Typ Task<TResult> oder ValueTask<TResult> ist. Wenn der Ausdruck t vom Typ Task oder ValueTask ist, ist await t vom Typ void. In beiden Fällen löst await t die Ausnahme erneut aus, wenn t eine Ausnahme auslöst.

Asynchrone Datenströme und verwerfbare Objekte

Sie können die await foreach-Anweisung verwenden, um einen asynchronen Datenstrom zu verarbeiten. Weitere Informationen finden Sie im Abschnitt foreach-Anweisung im Artikel Iterationsanweisungen.

Sie können die await using-Anweisung nutzen, um ein asynchron verwerfbares Objekt zu nutzen, d. h. ein Objekt eines Typs, der eine IAsyncDisposable-Schnittstelle implementiert. Weitere Informationen erhalten Sie im Abschnitt Verwenden von asynchron verwerfbar des Artikels Implementieren einer DisposeAsync-Methode.

Der Operator „await“ in der Methode „Main“

Die Main-Methode, die den Einstiegspunkt der Anwendung darstellt, kann Task oder Task<int> zurückgeben. Deshalb kann es sich um eine Async-Methode handeln, sodass Sie den Operator await im Text verwenden können. In früheren C#-Versionen können Sie den Wert der Eigenschaft Task<TResult>.Result der Instanz Task<TResult> abrufen, die von der entsprechenden Async-Methode zurückgegeben wird, um sicherzustellen, dass die Methode Main darauf wartet, dass ein asynchroner Vorgang abgeschlossen wird. Für asynchrone Vorgänge, für die kein Wert zurückgegeben wird, können Sie die Methode Task.Wait aufrufen. Informationen zum Auswählen der Sprachversion finden Sie unter Auswählen der C#-Sprachversion.

C#-Sprachspezifikation

Weitere Informationen finden Sie im Abschnitt Await-Ausdrücke der C#-Sprachspezifikation.

Weitere Informationen