Хорошо известно, что в библиотеке общего назначения ConfigureAwait(false)
следует использовать для каждого вызова ожидания, чтобы избежать продолжения текущего SynchronizationContext.
В качестве альтернативы переполнению всей базы кода с помощью ConfigureAwait(false)
можно просто установить значение SynchronizationContext равным null один раз, методом общедоступной поверхности и восстановить его перед возвратом пользователю. Другими словами:
public async Task SomeSurfaceMethod()
{
var callerSyncCtx = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
try
{
// Do work
}
finally
{
SynchronizationContext.SetSynchronizationContext(callerSyncCtx);
}
}
Это также можно обернуть в using
для лучшей читаемости.
Есть ли недостаток этого подхода, не приводит ли он к такому же эффекту?
Основным преимуществом является, очевидно, читаемость - удаление всех вызовов ConfigureAwait(false)
. Это также может снизить вероятность того, что вы забудете ConfigureAwait(false)
где-нибудь (хотя анализаторы смягчают это, и можно утверждать, что разработчики могли бы также забыть об изменении SynchronizationContext).
Несколько экзотическое преимущество - это не включение выбора захвата SynchronizationContext или не во всех методах. Другими словами, в одном случае я могу запустить метод X с SynchronizationContext, в то время как в другом я могу запустить один и тот же метод без него. Когда ConfigureAwait(false)
внедряется везде, что невозможно. Конечно, это довольно редкое требование, но я столкнулся с ним во время работы над Npgsql (вызвав этот вопрос).