TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #2568 2.32K
День 2124. #ЗаметкиНаПолях #Cancellation
Отмена. Часть 6: Связывание. Окончание

Начало
Продолжение

Не используйте OperationCanceledException.CancellationToken
Рассмотрим снова исходный пример:
async Task DoAsync(
CancellationToken ct)
{
using var cts =
CancellationTokenSource
.CreateLinkedTokenSource(ct);
var task = DoOtherAsync(cts.Token);
… // Что-то делаем
… // возможно вызываем cts.Cancel()
await task;
}

Предположим, код вызывает DoAsync и реагирует на отмену:
async Task MainAsync()
{
using var cts =
new CancellationTokenSource();
cts.CancelAfter(2000);

try
{
await DoAsync(cts.Token);
}
catch (OperationCanceledException ex)
// ПЛОХОЙ КОД!!!
when (ex.CancellationToken == cts.Token)
{
Console.WriteLine("Timeout!");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}

Замысел кода — сделать что-то особенное, если код отменяется из-за этого конкретного источника отмены. К сожалению, этот код проблематичен в реальном мире; DoAsync может использовать связанный источник токена отмены, в этом случае OperationCanceledException.CancellationToken не будет соответствовать cts.Token, даже если он был источником отмены!

Поэтому не используйте OperationCanceledException.CancellationToken. Правильное решение — проверять, запросил ли этот источник отмену:
async Task MainAsync()
{
…
catch (OperationCanceledException)
when (cts.IsCancellationRequested)
{
Console.WriteLine("Timeout!");
}
…
}


То же касается и проверки связанных источников отмены:
async Task DoAsync(
CancellationToken ct)
{
using var cts =
CancellationTokenSource
.CreateLinkedTokenSource(ct);
cts.CancelAfter(1000);

try
{
await DoOtherAsync(cts.Token);
}
catch (OperationCanceledException ex)
// ПЛОХОЙ КОД!!!
when (ex.CancellationToken == cts.Token)
{
… // делаем что-то при таймауте
throw;
}
}

С этим кодом та же проблема! Возможно, что DoAsync может сам использовать связанный токен отмены (или будет использовать в будущем). Решение — не использовать OperationCanceledException.CancellationToken:
async Task DoOtherAsync(
CancellationToken ct)
{
…
catch (OperationCanceledException ex)
when (cts.IsCancellationRequested)
{
… // делаем что-то при таймауте
throw;
}
}


Итого
В большинстве случаев не приходится использовать связанные токены отмены, но они бывают полезны. Вот, что следует запомнить:
1. Освобождайте (dispose) источники токенов отмены, включая связанные источники токенов отмены.
2. Не используйте OperationCanceledException.CancellationToken; вместо этого используйте IsCancellationRequested.
3. Для любого кода, который имеет несколько токенов в области действия, будьте внимательны к тому, на какой из них вы реагируете.

Источник: https://blog.stephencleary.com/2024/10/cancellation-6-linking.html
  • 👍 9
More from @netdeveloperdiary
  1. Oct 6, 2026🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собес…
  2. Oct 6, 2026День 2806. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Начало Больши…
  3. Oct 5, 2026День 2805. #ЧтоНовенького #NET11 Аргументы в Выражениях Коллекций в C#15 В C#15 реализован…
  4. Oct 4, 2026День 2804. #ВопросыНаСобеседовании Марк Прайс предложил свой набор из 60 вопросов (как тех…
  5. Oct 3, 2026Post #3360
  6. Oct 3, 2026День 2803. #Оффтоп Чем Заняться, Пока Работают Агенты? У VS Code Есть Ответ Сейчас большую…
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 →