Цель состоит в том, чтобы отсеять неправильное использование ConfigureAwait в очень большой базе кода.
Некоторые команды решают использовать инструмент анализа кода для этого.Есть несколько доступных.Самый распространенный подход, который я видел, это требовать a ConfigureAwait
для каждого await
и явно указывать либо true
, либо false
.Это гарантирует, что каждый await
был рассмотрен и поток контекста явный.Другие команды применяют специфичные для проекта правила «всегда использовать ConfigureAwait(false)
» и просто зависят от проверки кода для проектов, которые не могут следовать этому правилу.
Проблема с вашим примером кода состоит в том, что он невозможно для DoWhatever
, чтобы узнать, был ли он вызван косвенно, из-за Task.Run
.Если вы переписываете эти методы, это становится понятным:
public static async Task CapturesContext()
{
var task = Task.Run(() => DoWhatever());
await task;
}
public static async Task DoesNotCaptureContext()
{
var task = Task.Run(() => DoWhatever());
var configuredTask = task.ConfigureAwait(false);
await configuredTask;
}
Первые строки переписанных методов должны прояснить, что DoWhatever
не знает, будет ли CapturesContext
или DoesNotCaptureContext
захватывать контекст илине.Обратите внимание на «волю» (будущее время) - вполне возможно, что DoWhatever
выполняется и завершает выполнение до того, как ConfigureAwait(false)
даже будет вызван.
Теперь вы можете проверить изнутри задачи, выполняется ли она в контексте прямо сейчас .Но в этом случае для обоих примеров методов DoWhatever
не увидит контекст из-за Task.Run
.Так что это не поможет вам обнаружить тот факт, что CapturesContext
захватывает контекст;DoWhatever
не видит контекст, поэтому он не может его обнаружить.
Пользовательский SynchronizationContext
является хорошим решением для модульных тестов, но его было бы неудобно использовать во время выполнения, поскольку у вас естьнекоторые методы, которые нуждаются в контексте.По этой причине большинство групп предпочитают полагаться на проверку кода и / или инструменты анализа кода.