Улавливает ли TaskCanceledException и проверяет Task.Отменена хорошая идея?

#c# #.net #task-parallel-library #task #cancellation-token

#c# #.net #task-parallel-library #задача #отмена-токен

Вопрос:

В моей команде есть люди, которым действительно нравится кодирование с использованием async Task . И иногда им нравится использовать CancellationToken параметры.

В чем я не уверен, так это в том, должны ли мы как команда использовать этот стиль кода (A):

 async Task<someObject> DoStuff(CancellationToken t)
{
    while (!t.IsCanceled)
    {
        try {
            Task.Delay(5000, t);
        }
        catch (AggregateException e) // or is it TaskCanceledException or OperationCanceledException? I don't know? :)
        {
        }
        // poll something, return someObject, or null
    }
    return null;
}
  

Это, очевидно, означает, что вызывающий, вероятно, должен самостоятельно проверить токен отмены, чтобы определить, следует ли продолжать обработку, и им, возможно, придется обрабатывать повторные значения null:

 var retVal = await DoStuff(token);
if (token.IsCanceled) { ... }
  

Однако, если мы примем второй стиль кода (B), который полагается на TaskCanceledException:

 async Task<someObject> DoStuff(CancellationToken t)
{
    while(true)
    {
        Task.Delay(5000, t);
        // poll something, return someObject, or null
    }
}
  

Код реализации определенно проще — и вызывающий объект имеет возможность обрабатывать исключение или нет, в зависимости от обстоятельств… но я не могу не беспокоиться о том, что вызывающие могут забыть, что исключение TaskCanceledException — это то, о чем им нужно беспокоиться, и процессы могут завершиться сбоем в результате того, что они не перехватят эти исключения (в потоках переднего плана или фона).

Итак, мой чересчур оптимистично сформулированный вопрос таков: какой, по вашему мнению, лучший стиль, который все должны всегда использовать, и почему? 🙂

Комментарии:

1. Меня интересует ответ (ы) на этот вопрос, и у меня тоже есть свой собственный, но я подозреваю, что этот вопрос запрашивает мнение, которое не совсем соответствует теме для SO. Рассматривали ли вы возможность запросить помощь модератора в переносе этого в codereview вместо этого?

2. Я думаю, что мнение полностью соответствует теме для SO в случае «что, по вашему мнению, является хорошей практикой программирования».

3. Я также не считаю это вопросом проверки кода, поскольку он нацелен на конкретную тему, это не «скажите мне, как лучше это закодировать».

4. Я не испытывал по этому поводу особых чувств; это просто выглядело похоже на субъективный вопрос (ы), которые были отмечены в прошлом. Я рад, что это получает хорошее обсуждение 🙂

5. @TimLovell-Smith, вы никогда не должны проглатывать AggregateException , как в вашем коде, без проверки внутренних исключений. Кроме того, это может быть либо OperationCanceledException , либо TaskCanceledException . Проверьте этот документ: Использование поддержки отмены в .NET 4.0 .

Ответ №1:

В .Сама Net framework, когда вы передаете a CancellationToken в качестве параметра, вы получите обратно a TaskCanceledException . Я бы не пошел против этого и не создал свой собственный шаблон проектирования, потому что люди, которые знакомы с .Net будет знаком с вашим кодом.

Мое руководство таково: тот, который отменяет токен, должен обрабатывать TaskCanceledException , поэтому, если вы используете CancellationToken внутри своего метода по своим собственным причинам, продолжайте и используйте try-catch блок. Но если вы получаете токен в качестве параметра, пусть генерируется исключение.

Комментарии:

1. Отличный ответ за включение руководства по кодированию для обеспечения обработки исключений!

2. Хороший ответ — но было бы неплохо увидеть несколько примеров кода в том же духе, что и вопрос организации.

3. Кроме того, обычно рекомендуется перехватывать, OperationCanceledException как указано в статье «Рекомендуемые шаблоны для CancellationToken» (раздел «Обработка исключений отмены»).