Существует множество рекомендаций по использованию ConfigureAwait(false)
при использовании await/async на С#.
Похоже, что общая рекомендация заключается в использовании ConfigureAwait(false)
в коде библиотеки, поскольку она редко зависит от контекста синхронизации.
Однако предположим, что мы пишем очень общий код полезности, который принимает функцию в качестве входного. Простым примером могут быть следующие (неполные) функциональные комбинаторы, упрощающие простые задачи:
Карта
public static async Task<TResult> Map<T, TResult>(this Task<T> task, Func<T, TResult> mapping)
{
return mapping(await task);
}
FlatMap:
public static async Task<TResult> FlatMap<T, TResult>(this Task<T> task, Func<T, Task<TResult>> mapping)
{
return await mapping(await task);
}
Вопрос в том, следует ли использовать ConfigureAwait(false)
в этом случае? Я не уверен, как работает захват контекста. замыкания.
С одной стороны, если комбинаторы используются функционально, контекст синхронизации не нужен. С другой стороны, люди могут злоупотреблять API и делать контекстно-зависимые вещи в предоставляемых функциях.
Один вариант - иметь отдельные методы для каждого сценария (Map
и MapWithContextCapture
или что-то еще), но он кажется уродливым.
Другим вариантом может быть добавление опции map/flatmap из и в ConfiguredTaskAwaitable<T>
, но поскольку awaitables не должны реализовывать интерфейс, это приведет к большому избыточному коду и, на мой взгляд, будет даже хуже.
Есть ли хороший способ переключить ответственность на вызывающего, так что внедренной библиотеке не нужно делать какие-либо предположения о том, нужен ли контекст в предоставляемых функциях отображения?
Или это просто факт, что асинхронные методы не слишком сложны, без различных предположений?
ИЗМЕНИТЬ
Просто чтобы прояснить несколько вещей:
- Проблема существует. Когда вы выполняете "обратный вызов" внутри функции утилиты, добавление
ConfigureAwait(false)
приведет к нулевой синхронизации. контекст. - Основной вопрос - как мы должны справляться с ситуацией. Следует ли игнорировать тот факт, что кто-то может захотеть использовать синхронизацию. контекст, или есть хороший способ переложить ответственность на вызывающего, кроме добавления некоторой перегрузки, флага или тому подобного?
Как упоминалось в нескольких ответах, можно было бы добавить в метод флаг bool, но, как я вижу, это тоже не слишком красиво, поскольку его нужно будет распространять полностью через API ( так как есть больше "полезных" функций, в зависимости от показанных выше).