Многие из них обертывают ванильные асинхронные стилизованные методы, которые принимают делегат обратного вызова, который будет вызван после его завершения.
Обратите внимание, что не только Task
, но и все экземпляры типов, которые соответствуют следующим правилам, могут быть await
ed:
Должен быть метод AWAITER GetAwaiter()
, вызываемый из экземпляра await
ed (который также измеряет метод расширения), в то время как AWAITER
представляет любые типы, соответствующие правилам.
AWAITER
должен реализовать INotifyCompletion
, чтобы принять делегата обратного вызова, который должен быть вызван в асинхронной задаче.
AWAITER
экземпляр должен иметь bool IsCompleted { get; }
, определенный для проверки его завершения.
AWAITER
экземпляр должен иметь метод RESULT GetResult()
, определенный для завершения await
ing, в то время как RESULT
будет типом результата выражения await
, которое может быть void
, если нет результата вернулся.
Например:
public static TaskAwaiter<T> GetAwaiter<T>(this T target) => Task.FromResult(target).GetAwaiter();
Этот метод позволил всем типам быть await
ed, что мгновенно завершалось бы, получая само значение.
var x = await 1; // int x = 1;
Любые типы, которые соответствуют правилам, могут быть await
ed, что означает, что вы можете реализовать его самостоятельно для вызова делегата обратного вызова вручную без асинхронного метода.
Стандартный API предоставляет TaskCompletionSource<TResult>
для преобразования асинхронных операций обратного вызова в Task
, и вам может не потребоваться реализовать собственный ожидаемый тип, но знание того, какой синтаксис await
на самом деле позволяет вам обрабатывать больше случаев.