TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.76K subscribers
Post #1200 1.4K
День девятьсот семьдесят восьмой. #ЗаметкиНаПолях #AsyncTips
В этой серии постов будут выдержки из книги Стивена Клири. Просто разнообразные советы по работе с асинхронным кодом.

Возвращение завершённых задач
Задача:
реализовать синхронный метод с асинхронной сигнатурой. Например, при модульном тестировании асинхронного кода, когда нужна простая заглушка или имитированная реализация для асинхронного интерфейса.

Решение:
1. Для возврата значения - использовать Task.FromResult:
public Task<int> GetValueAsync()
=> Task.FromResult(42);

2. Для методов, не имеющих возвращаемого значения - Task.CompletedTask:
public Task DoSomethingAsync()
=> Task.CompletedTask;

3. Для возврата исключения - Task.FromException:
public Task<T> ThrowsAsync<T>()
=> Task.FromException<T>(new Exception());

4. Для отменённых задач - Task.FromCanceled:
public Task<int> GetValueAsync(CancellationToken ct) {
if (ct.IsCancellationRequested)
return Task.FromCanceled<int>(ct);

return Task.FromResult(13);
}

Если в синхронной реализации может произойти отказ, перехватывайте исключения и используйте Task.FromException:
public Task DoSomethingAsync() {
try {
DoSomethingSynchronously();
return Task.CompletedTask;
}
catch (Exception ex)
{
return Task.FromException(ex);
}
}

Если вы реализуете асинхронный интерфейс синхронным кодом, избегайте любых форм блокировки. Избегайте блокирования с последующим возвращением завершённой задачи в асинхронном методе, если метод может быть реализован асинхронно. Если асинхронный метод блокируется, он не позволяет вызывающему потоку запускать другие задачи, что противоречит идее конкурентности и может привести к взаимоблокировке.

Если вы регулярно используете Task.FromResult, задачу можно кэшировать, чтобы не создавать объекты Task каждый раз:
private static readonly Task<int> zeroTask 
= Task.FromResult(0);
…
Task<int> GetValueAsync()
=> zeroTask;

На логическом уровне Task.FromResult, Task.FromException и Task.FromCanceled являются вспомогательными методами и сокращёнными формами обобщённого типа TaskCompletionSource<T>. TaskCompletionSource<T> представляет собой низкоуровневый тип, полезный для взаимодействия с другими формами асинхронного кода. В общем случае следует применять сокращенную форму Task.FromResult и родственные формы, если хотите вернуть уже завершённую задачу. TaskCompletionSource<T> используется для возвращения задачи, которая завершается в некоторый момент в будущем.

Помимо этого, иногда требуется протестировать асинхронное поведение метода. В этом поможет Task.Yield. Заметьте, что в отличие от вышеупомянутых методов, этот метод помечен как асинхронный и содержит await:
public async Task<int> DoSomethingAsync()
{
// Принудительно включить асинхронное поведение
await Task.Yield();
return 13;
}

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 2.
More from @netdeveloperdiary
  1. Oct 13, 2026День 2813. #ЗаметкиНаПолях #Async Ещё Раз Про Async/Await в C#. Часть 1 1. Почему существу…
  2. Oct 12, 2026День 2812. #Карьера #AI Как Разработчикам Оставаться Полезными, Когда Код Пишет ИИ? По мер…
  3. Oct 11, 2026День 2811. #ВопросыНаСобеседовании Марк Прайс предложил свой набор из 60 вопросов (как тех…
  4. Oct 10, 2026День 2810. #ЧтоНовенького #VSCode Более Быстрый и Лёгкий C# Dev Kit Мы, разработчики, люби…
  5. Oct 9, 2026День 2809. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Окончание Начало 3.…
  6. Oct 8, 2026День 2808. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Начало В ИТ есть се…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →