Има доста насоки кога да се използва ConfigureAwait(false) при ползване на async/await в C#.
Основната препоръка е да се използва ConfigureAwait(false) в библиотеки,тъй като рядко зависи от synchronization context-а.
Обаче пишем много generic код, който приема функция като вход. Прост пример може да бъде следния код на комбинатори:
Map:
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) в този случай? Не съм сигурен как context capture работи.
От една страна, ако комбинаторите се ползват по функционален начин, synchronization context ще е излишен. От друга страна, хората може да използват неправилно апито и да правят неща,зависими от контекста.
Единият вариант е да има отделни методи за всеки случай (Map или MapWithContextCapture), ама изглежда грозно.
Друг вариант е да се добави опция map/flatmap от и в ConfiguredTaskAwaitable<T>,но тъй като нещата, които се await-ват не трябва да имплементират интерфейс това би се оказано доста излишен код и според мен е още по-зле.
Проблемът е следния- когато се изпълни колбек във функцията, добавянето на ConfigureAwait(false) ще доведе до null synchronization context. Имах идея да добавя булев флаф в метода, но не е много красиво,а и ще се разнася из цялото апи, тъй като доста функции зависят от тези горе.
Има ли добър начин да сменя функционалността на извикващия метод, така че имплементираната библиотека да не се интересува дали се използва контекста в подадените функции?
Как да се справя с тази ситуация? Да игнорирам ли факта, че някой може да използва sync контекста или има по-добър начин да сменя отговорността към извикващия метод, без да правя overload, булев флаг или нещо подобно