Должен ли я предпочесть бросить или вернуться при запросе отмены?
Рассмотрим два следующих подхода к обработке отмены через CancellationToken
:
public async Task DoAllAvailableWork(CancellationToken cancelToken)
{
foreach (var job in GetAllAvailableWork())
{
await job.Process();
if (cancelToken.IsCancellationRequested())
return;
}
}
public async Task DoAllAvailableWork(CancellationToken cancelToken)
{
foreach (var job in GetAllAvailableWork())
{
await job.Process();
cancelToken.ThrowIfCancellationRequested();
}
}
В этом случае job.Process()
выполняет какую-то атомарную работу, которую нельзя или нельзя остановить после начала, поэтому он не принимает CancellationToken
,
Есть ли основания предпочитать один из этих подходов другому? Если да, какой подход должен быть предпочтительным?
проверка IsCancellationRequested()
и возвращение кажется мне чище, в том смысле, что бросание подразумевает, что что-то пошло не так, и отмена - это случай, который мы явно планировали обработать (поэтому мы принимаем CancellationToken
). С другой стороны, вызывающий абонент не обязательно может знать, какой подход мы выберем, поэтому он должен настроить try/catch для OperationCancelledException
независимо от того, какой вариант мы выберем.
1 ответ
ThrowIfCancellationRequested
был разработан для продолжения задач. Бросок останавливает всю цепочку продолжения (за исключением продолжений обработки отмены). Необработанный OperationCancelledException
в задании отменит Task
Токен отмены также (если есть).
В вашем случае нет Task
, Вы можете определить свой собственный интерфейс. Но имейте в виду, что тот, кто вызывает ваш метод, должен также иметь возможность увидеть, была ли ваша операция отменена или нет - в конце концов, что-то еще должно было вызвать отмену, если все, что у вас есть, - синхронные методы. В зависимости от того, что означает отмена, возвращая ошибку, пустой результат, ложь или выбрасывая исключение (но, вероятно, нет OperationCancelledException
в любом случае!) каждый из них имеет смысл - вам нужно адаптировать его к тому типу интерфейса, который вы создаете.