23

我的团队中有一些人非常喜欢使用 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 retVals:

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

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

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

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

所以,我过于乐观的问题是:你认为哪种风格是每个人都应该经常使用的最佳风格,为什么?:)

4

1 回答 1

38

在 .Net 框架本身中,当您将 aCancellationToken作为参数传递时,您将返回一个TaskCanceledException. 我不会反对这一点并创建自己的设计模式,因为熟悉 .Net 的人会熟悉您的代码。

我的指导方针是:取消令牌的那个是应该处理 的那个TaskCanceledException,所以如果您CancellationToken出于自己的原因在方法内部使用 a,请继续使用try-catch块。但是如果你获取token作为参数,就让异常被抛出

于 2014-07-03T17:03:24.743 回答