await (C#-Referenz)

Der Operator await wird auf eine Aufgabe in einer asynchronen Methode angewendet, um einen Unterbrechungspunkt in die Ausführung der Methode einzufügen, bis die Aufgabe abgeschlossen ist. Die Aufgabe stellt derzeit ausgeführte Arbeit dar.

await kann nur in einer asynchronen Methode verwendet werden, die vom Schlüsselwort async verändert wird. Eine solche mit dem async-Modifizierer definierte Methode, die in der Regel mindestens einen await-Ausdruck enthält, wird als asynchrone Methode bezeichnet.

Hinweis

Die Schlüsselwörter async und await wurden in C# 5 eingeführt. Eine Einführung in die asynchrone Programmierung finden Sie unter Asynchronous Programming with async and await (Asynchrone Programmierung mit „async“ und „await“).

In der Regel wird die Aufgabe, auf die Sie den Operator await anwenden, von einem Aufruf einer Methode zurückgegeben, die das aufgabenbasierte asynchrone Muster implementiert. Dazu zählen Methoden, die die Objekte <xref:System.Threading.Tasks.Task>, <xref:System.Threading.Tasks.Task%601> und System.Threading.Tasks.ValueType<TResult> zurückgeben.

Im folgenden Beispiel gibt die <xref:System.Net.Http.HttpClient.GetByteArrayAsync%2A?displayProperty=fullName>-Methode ein Task<byte[]>-Objekt zurück. Diese Aufgabe enthält das Versprechen, das tatsächliche Bytearray zu erzeugen, wenn die Aufgabe abgeschlossen ist. Der await-Operator hält die Ausführung an, bis die Arbeit der Methode <xref:System.Net.Http.HttpClient.GetByteArrayAsync%2A> abgeschlossen ist. In der Zwischenzeit wird die Steuerung wieder an den Aufrufer von GetPageSizeAsync übergeben. Wenn der Task die Ausführung beendet, wird der await-Ausdruck zu einem Bytearray ausgewertet.

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      string[] args = Environment.GetCommandLineArgs();
      if (args.Length > 1)
         GetPageSizeAsync(args[1]).Wait();
      else
         Console.WriteLine("Enter at least one URL on the command line.");
   }

   private static async Task GetPageSizeAsync(string url)  
   {  
       var client = new HttpClient();  
       var uri = new Uri(Uri.EscapeUriString(url));
       byte[] urlContents = await client.GetByteArrayAsync(uri);
       Console.WriteLine($"{url}: {urlContents.Length/2:N0} characters");  
   }  
}
// The following call from the command line:
//    await1 http://docs.microsoft.com
// displays output like the following: 
//   http://docs.microsoft.com: 7,967 characters


Wichtig

Das vollständige Beispiel finden Sie unter Exemplarische Vorgehensweise: Zugreifen auf das Web mit Async und Await. Sie können das Beispiel aus den Codebeispielen für Entwickler der Microsoft-Website herunterladen. Das Beispiel befindet sich im AsyncWalkthrough_HttpClient-Projekt.

Wenn await auf das Ergebnis eines Methodenaufrufs angewendet wird, der Task<TResult> zurückgibt, ist der Typ des await-Ausdrucks TResult, wie im vorherigen Beispiel gezeigt. Wenn await auf das Ergebnis eines Methodenaufrufs angewendet wird, der Task zurückgibt, ist der Typ des await-Ausdrucks void. Der Unterschied wird im folgenden Beispiel veranschaulicht.

// await keyword used with a method that returns a Task<TResult>.  
TResult result = await AsyncMethodThatReturnsTaskTResult();  

// await keyword used with a method that returns a Task.  
await AsyncMethodThatReturnsTask();  

// await keyword used with a method that returns a ValueTask<TResult>.
TResult result = await AsyncMethodThatReturnsValueTaskTResult();

Ein await-Ausdruck blockiert nicht den Thread, auf dem er ausgeführt wird. Stattdessen bewirkt er, dass der Compiler den Rest der asynchronen Methode als Fortsetzung der erwarteten Aufgabe registriert. Die Steuerung wird dann wieder an den Aufrufer der Async-Methode übergeben. Wenn die Aufgabe abgeschlossen ist, löst sie ihre Fortsetzung aus, und die Ausführung der asynchronen Methode wird da fortgesetzt, wo sie angehalten wurde.

Ein await-Ausdruck kann nur in seiner einschließenden Methode, einem Lambdaausdruck oder einer anonymen Methode auftreten, die durch einen async-Modifizierer gekennzeichnet sein muss. Der Begriff await dient nur in diesem Kontext als Schlüsselwort. In anderen Kontexten wird er als Bezeichner interpretiert. Innerhalb der Methode, des Lambdaausdrucks oder der anonymen Methode kann ein await-Ausdruck nicht im Textteil einer synchronen Funktion, einem Abfrageausdruck, im Block einer lock-Anweisung oder in einem unsicheren Kontext auftreten.

Ausnahmen

Die meisten asynchronen Methoden geben einen <xref:System.Threading.Tasks.Task> oder <xref:System.Threading.Tasks.Task%601> zurück. Die Eigenschaften der zurückgegebenen Aufgabe enthalten Informationen über den Status und Verlauf, z. B. ob die Aufgabe abgeschlossen ist, ob die asynchrone Methode eine Ausnahme verursacht hat oder abgebrochen wurde, und was das Endergebnis ist. Der Operator await greift auf diese Eigenschaften zu, indem er Methoden auf dem von der GetAwaiter-Methode zurückgegebenen Objekt aufruft.

Wenn Sie auf eine asynchrone Methode warten, die eine Aufgabe zurückgibt und eine Ausnahme verursacht, löst der Operator await die Ausnahme erneut aus.

Wenn Sie auf eine asynchrone Methode warten, die eine Aufgabe zurückgibt und abgebrochen wird, löst der Operator await erneut eine <xref:System.OperationCanceledException> aus.

Eine einzelne Aufgabe, die einen Fehlerzustand aufweist, kann verschiedene Ausnahmen auslösen. Beispielsweise kann die Aufgabe das Ergebnis eines Aufrufs an <xref:System.Threading.Tasks.Task.WhenAll%2A?displayProperty=fullName> sein. Wenn Sie auf eine solche Aufgabe warten, löst die await-Operation nur eine der Ausnahmen erneut aus. Sie können jedoch nicht vorhersagen, welche der Ausnahmen erneut ausgelöst wird.

Beispiele für die Fehlerbehandlung in asynchronen Methoden finden Sie unter try-catch.

Beispiel

Im folgenden Beispiel wird die Gesamtzahl der Zeichen auf den Seiten zurückgegeben, deren URLs als Befehlszeilenargumente übergeben werden. Im Beispiel wird die Methode GetPageLengthsAsync aufgerufen, die mit dem Schlüsselwort async gekennzeichnet ist. Die Methode GetPageLengthsAsync verwendet wiederum das Schlüsselwort await, um auf Aufrufe der Methode <xref:System.Net.Http.HttpClient.GetStringAsync%2A?displayProperty=fullName> zu warten.

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

class Example
{
   static void Main()
   {
      string[] args = Environment.GetCommandLineArgs();
      if (args.Length < 2)
         throw new ArgumentNullException("No URLs specified on the command line.");
      
      long characters = GetPageLengthsAsync(args).Result;
      Console.WriteLine($"{args.Length - 1} pages, {characters:N0} characters");
   }

   private static async Task<long> GetPageLengthsAsync(string[] args)
   {
      var client = new HttpClient();
      long pageLengths = 0;

      for (int ctr = 1; ctr < args.Length; ctr++) {
         var uri = new Uri(Uri.EscapeUriString(args[ctr]));
         string pageContents = await client.GetStringAsync(uri);
         Interlocked.Add(ref pageLengths, pageContents.Length);
      }
      return pageLengths;
   }
}

Da die Verwendung von async und await an einem Anwendungseinstiegspunkt nicht unterstützt wird, kann das async-Attribut nicht auf die Main-Methode angewendet werden und es kann auch nicht auf den Methodenaufruf GetPageLengthsAsync gewartet werden. Es kann sichergestellt werden, dass die Main-Methode auf den Abschluss des asynchronen Vorgangs wartet, indem der Wert der Eigenschaft <xref:System.Threading.Tasks.Task%601.Result?displayProperty=fullName> abgerufen wird. Bei Aufgaben, die keinen Wert zurückgeben, wird die Methode <xref:System.Threading.Tasks.Task.Wait%2A?displayProperty=fullName> aufgerufen.

Siehe auch

Asynchrone Programmierung mit Async und Await
Exemplarische Vorgehensweise: Zugreifen auf das Web mit Async und Await
async