Простейшая реализация шаблона await
public class MyAwaitableType
{
public MinimalAwaiter GetAwaiter()
{
return new MinimalAwaiter();
}
public class MinimalAwaiter : INotifyCompletion
{
public bool IsCompleted => true;
public string GetResult() => "This is a result";
public void OnCompleted(Action continuation)
{
throw new NotImplementedException();
}
}
}
Листинг 17.15 показывает минимальную рабочую реализацию шаблона await. Она чрезмерно упрощена, так как всегда завершается синхронно, поэтому ее метод OnCompleted ничего не делает. Фактически при использовании шаблона await этот метод никогда не будет вызываться, поэтому у меня он вызывает исключение. И хотя этот пример крайне прост, он служит прекрасной иллюстрацией того, что делает await
Различие между этими интерфейсами и их соответствующими методами заключается в том, что первый требует, чтобы ожидающий передавал текущий контекст выполнения целевому методу, а последний — нет.
Вам придется реализовать INotifyCompletion, а еще есть дополнительный интерфейс, который тоже рекомендуется по возможности реализовать. Он называется ICriticalNotifyCompletion. Они выполняют похожие задачи: каждый определяет один метод (OnCompleted и UnsafeOnCompleted соответственно), который принимает единственный делегат Action, и ожидающий должен вызывать этот делегат после завершения операции.
Компилятору также нужен способ получить результат после завершения работы, поэтому у ожидающего должен быть метод GetResult. Его возвращаемый тип определяет тип результата операции — это будет тип выражения await.
тот метод должен возвращать объект или значение, которое называется ждущим и выполняет три действия.
Во-первых, ждущий объект должен предоставить свойство типа bool с именем IsCompleted.
Компилятор ожидает, что операнд ключевого слова await будет типом, который содержит метод с именем GetAwaiter.
Вызов пользовательской реализации await
static async Task UseCustomAsync()
{
string result = await CustomAsync();
Console.WriteLine(result);
}
public static MyAwaitableType CustomAsync()
{
return new MyAwaitableType();
}
Асинхронная лямбда
okButton.Click += async (s, e) =>
{
using (HttpClient w = this.clientFactory.CreateClient())
{
infoTextBlock.Text = await w.GetStringAsync(uriTextBox.Text);
}
};
Так же как ключевое слово await может использовать любой асинхронный метод, который соответствует определенному шаблону (см. далее), C# предлагает такую же гибкость в применении к реализации асинхронного метода. Вы не ограничены Task, Task, ValueTask и ValueTask. Вы можете вернуть любой тип, который удовлетворяет двум условиям: он должен быть аннотирован атрибутом AsyncMethodBuilder, определяющим класс, который компилятор может использовать для управления ходом выполнения и завершением задачи, а также содержать метод GetAwaiter, который возвращает тип, реализующий интерфейс ICriticalNotifyCompletion.