В нашем старом синхронном приложении в нашем базовом классе было следующее:
public virtual bool ShouldSomethingHappen() => false;
Итак, идея заключается в том, что в производном классе в БД может быть вызван вызов, чтобы определить, должно ли что-то произойти.
Итак, при переходе на ожидаемый код мы сначала попробовали следующее в базовом классе:
public virtual async Task<bool> ShouldSomethingHappen()
{
await Task.Yield();
return false;
}
Казалось, что это хорошо работает при запуске приложения, но оно нарушило наши интеграционные тесты (где у нас много ожидаемых вызовов).... мы не могли понять, почему.
Но, изменив это на следующее, исправлена проблема:
public virtual async Task<bool> ShouldSomethingHappen() => Task.FromResult(false);
Так технически, какая разница между этими двумя подходами?
Может быть, все, что было в ваших тестах интеграции после await Task.Yield()
не предназначено для работы с другим потоком. Task.Yield()
заставляет метод продолжать использовать остальную часть метода в другом потоке. Когда вы используете Task.FromResult
вы возвращаете уже завершенную задачу. Вы просто возвращаете завершенную задачу, поэтому она все равно происходит в одном и том же потоке.
Вы можете проверить это, изменив Task.FromResult(false)
на Task.FromResult(false).ConfigureAwait(false)
.await Task.Delay(n).ConfigureAwait(false)
await Task.Delay(10).ConfigureAwait(false)
просто для подтверждения.
async
которую можно было бы упростить дляpublic virtual Task<bool> ShouldSomethingHappen() => Task.FromResult(false);
, Если на самом деле ничего не ожидается, нет необходимости помечать вызовasync
async
не является частью подписи. Хорошо иметь простой виртуальный метод (неasync
), который возвращаетTask
и некоторый производный тип может переопределить этот метод с помощьюasync
реализации.