День двести пятнадцатый. #ЗаметкиНаПолях
Многопоточность.
9. Async/await. Продолжение
Паттерн awaitable
Паттерн awaitable используется для определения типов, которые можно использовать с оператором
1.
2. Awaiter должен реализовывать
3. Awaiter должен иметь свойство
4. Awaiter должен иметь метод
5. Этим не обязательно быть открытыми, но они должны быть доступны из асинхронного метода, в котором используется await.
6. Тип результата выражения
Рассмотрим статический метод
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 5.
Многопоточность.
9. Async/await. Продолжение
Паттерн awaitable
Паттерн awaitable используется для определения типов, которые можно использовать с оператором
await
. Можно было бы ожидать интерфейса вроде IDisposable
для оператора using
. Однако поддержка await
основана на шаблоне. Допустим, есть выражение типа T
, которое необходимо ожидать. Компилятор выполняет следующие проверки:1.
T
должен иметь метод GetAwaiter()
без параметров, либо должен существовать метод расширения, принимающий один параметр типа T
. Метод GetAwaiter
не должен быть пустым. Тип возвращаемого значения метода называется awaiter («ожидатель»).2. Awaiter должен реализовывать
System.Runtime.INotifyCompletion
, имеющий единственный метод: void OnCompleted(Action)
.3. Awaiter должен иметь свойство
IsCompleted
типа bool
.4. Awaiter должен иметь метод
GetResult()
без параметров.5. Этим не обязательно быть открытыми, но они должны быть доступны из асинхронного метода, в котором используется await.
6. Тип результата выражения
await
определяется типом результата метода GetResult
. Если это тип void
, значит await
не возвращает значения.Рассмотрим статический метод
Task.Yield()
. В отличие от большинства других методов класса Task
, метод Yield()
возвращает не задачу, структуру YieldAwaitable
. Вот упрощенная версия задействованных типов:public class Task
{
…
public static YieldAwaitable Yield();
}
public struct YieldAwaitable
{
public YieldAwaiter GetAwaiter();
public struct YieldAwaiter : INotifyCompletion
{
public bool IsCompleted { get; }
public void OnCompleted(Action continuation);
public void GetResult();
}
}
YieldAwaitable
следует паттерну awaitable, описанному ранее. Поэтому можно вызвать:await Task.Yield();
GetResult
структуры YieldAwaiter
возвращает void
, поэтому код выше не имеет результата. То есть следующий код недопустим:var result = await Task.Yield();Продолжение следует…
Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 5.