Ответ
Для отмены асинхронных операций в C# используется паттерн Cooperative Cancellation на основе CancellationTokenSource и CancellationToken. Отмена является запросом, а не принудительной остановкой потока.
Базовый паттерн
- Создание источника отмены:
CancellationTokenSource cts = new(); - Получение токена:
CancellationToken token = cts.Token; - Передача токена в асинхронный метод.
- Запрос отмены: Вызов
cts.Cancel()илиcts.CancelAfter(timeout). - Реакция на отмену внутри метода: периодическая проверка
token.ThrowIfCancellationRequested()илиtoken.IsCancellationRequested.
Пример: Отмена длительной операции
public async Task ProcessDataAsync(CancellationToken cancellationToken)
{
for (int i = 0; i < 100; i++)
{
// 1. Проверяем запрос на отмену. Если он был, выбрасывается OperationCanceledException.
cancellationToken.ThrowIfCancellationRequested();
// 2. Или проверяем флаг для более гибкой логики (например, graceful shutdown).
if (cancellationToken.IsCancellationRequested)
{
// Выполняем очистку ресурсов...
break;
}
// Полезная работа...
await Task.Delay(100, cancellationToken); // Task.Delay также поддерживает отмену.
}
}
// Использование
async Task MainMethod()
{
using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(5)); // Автоотмена через 5 секунд.
try
{
await ProcessDataAsync(cts.Token);
Console.WriteLine("Операция завершена успешно.");
}
catch (OperationCanceledException) // Ловим именно этот тип исключения.
{
Console.WriteLine("Операция была отменена.");
}
}
Ключевые моменты
- Распространение токена: Все асинхронные методы в цепочке вызовов должны принимать и передавать
CancellationTokenдальше, если это возможно. - Поддержка в библиотеках: Многие методы в .NET (например,
HttpClient.SendAsync,Stream.ReadAsync,DbContext.SaveChangesAsync) имеют перегрузки с параметромCancellationToken. Всегда используйте их. - Использование
using:CancellationTokenSourceреализуетIDisposable. Всегда оборачивайте его вusingили вызывайтеDispose()для своевременного освобождения ресурсов таймера. - Исключение
TaskCanceledException: Является производным отOperationCanceledException. Некоторые API (например,HttpClient) бросают именно его. Ловите базовыйOperationCanceledException.
Важно: Этот механизм не убивает поток. Он лишь устанавливает флаг, который ваша кодовая логика должна корректно обработать.