捕获TaskCanceledException并检查Task.Canceled是个好主意?

Tim*_*ith 21 .net c# task task-parallel-library cancellation-token

我团队中有些人非常喜欢使用异步编码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;
}
Run Code Online (Sandbox Code Playgroud)

这显然意味着调用者可能必须自己检查取消令牌以确定是否继续处理,并且他们可能必须处理null retVals:

var retVal = await DoStuff(token);
if (token.IsCanceled) { ... }
Run Code Online (Sandbox Code Playgroud)

但是,如果我们采用依赖于TaskCanceledException的第二种代码(B):

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

实现代码肯定更简单 - 调用者可以选择是否处理异常,但是我不禁担心调用者可能会忘记 TaskCanceledException是他们不得不担心的事情,并且进程可能会崩溃因为他们没有捕获这些异常(在前台或后台线程上).

所以,我过于乐观的措辞是:你认为哪个是每个人应该总是使用的最佳风格,为什么?:)

i3a*_*non 31

在.Net框架本身,当你传递CancellationToken一个参数时,你会得到一个TaskCanceledException.我不会反对这种情况并创建我自己的设计模式,因为熟悉.Net的人会熟悉您的代码.

我的指导原则是:取消令牌的那个是应该处理令牌的那个TaskCanceledException,所以如果你CancellationToken出于自己的原因在你的方法中使用,请继续使用try-catch块.但是如果您将令牌作为参数,则抛出异常.

  • 包含编码指南以确保处理异常的绝佳答案! (5认同)
  • 另外,按照[“ CancellationToken的推荐模式”](https://blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/recommended-patterns-for -cancellationtoken /)文章(“处理取消例外”部分)。 (2认同)