CancellationToken的默认参数


96

我有一些要添加的异步代码CancellationToken。但是,在许多实现中都不需要这样做,因此我想有一个默认参数-也许CancellationToken.None。然而,

Task<x> DoStuff(...., CancellationToken ct = null)

产量

不能将类型“”的值用作默认参数,因为没有对“ System.Threading.CancellationToken”类型的标准转换

Task<x> DoStuff(...., CancellationToken ct = CancellationToken.None)

“ ct”的默认参数值必须是编译时常量

有什么办法可以为其设置默认值CancellationToken吗?

Answers:


151

事实证明,以下工作原理:

Task<x> DoStuff(...., CancellationToken ct = default(CancellationToken))

其中,根据文档,被解释一样CancellationToken.None

您还可以使用C#default(CancellationToken)语句创建一个空的取消令牌。


4
这正是框架当前内部执行的操作,但是我不会在代码中执行。想一想,如果Microsoft更改了代码的实现,代码会发生什么变化,而CancellationToken.None不仅仅是default(CancellationToken)
noseratio 2014年

10
@Noseratio这将在很大程度上破坏向后兼容性,因此我不希望发生这种情况。还有什么default(CancellationToken)呢?
2013年

3
@Noseratio:你太死板了。没准CancellationToken.None会成为事实已过时。甚至Microsoft也在使用default(CancellationToken)。例如,从实体框架的源代码中查看这些搜索结果
drowa 2015年

21
从MSDN CancellationToken.None属性“您还可以使用C#default(CancellationToken)语句创建一个空的取消令牌”。在未来的C#版本将其作为默认参数之前,没有一个错误。
MuiBienCarlota

5
同样在这里 为了弥补两名失踪的中间组合,开发者可以通过无或为的CancellationToken的参数的CancellationToken和空时进度参数的默认。
Arek Bal

25

有没有办法为CancellationToken设置默认值?

不幸的是,这是不可能的,因为CancellationToken.None编译时间常数不是,这是可选参数中默认值的要求。

但是,可以通过重载方法而不是尝试使用默认参数来提供相同的效果:

Task<x> DoStuff(...., CancellationToken ct)
{
    //...
}

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}

6
这是处理此问题的推荐方法,如MSDN上基于任务的异步模式文档(特别是在选择要提供的重载部分中)所述。
Sam Harwell 2014年

CancellationToken.None ==默认true
eoleary

5
怎么了CancellationToken cancellationToken = default(CancellationToken)?此处也描述了blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…–
Ray

20

以下是按一般善意降序排列的几种解决方案:

1. default(CancellationToken)用作默认值:

Task DoAsync(CancellationToken ct = default(CancellationToken)) {  }

从语义上讲,CancellationToken.None它将是默认值的理想候选者,但不能这样使用,因为它不是编译时常量。default(CancellationToken)其次是最好的事情,因为它是一个编译时常量,并且正式证明与等效CancellationToken.None

2.提供不带CancellationToken参数的方法重载:

或者,如果你在可选参数宁愿方法重载(见有关该主题的问题):

Task DoAsync(CancellationToken ct) {  } // actual method always requires a token
Task DoAsync() => DoAsync(CancellationToken.None); // overload producing a default token

对于接口方法,可以使用扩展方法来实现:

interface IFoo
{
    Task DoAsync(CancellationToken ct);
}

static class Foo
{
    public static Task DoAsync(this IFoo foo) => foo.DoAsync(CancellationToken.None);
}

这样可以使接口更苗条,并使实现者不必明确编写转发方法重载。

3.使参数可null为空并用作默认值:

Task DoAsync(…, CancellationToken? ct = null)
{
     ct ?? CancellationToken.None 
}

我之所以喜欢这种解决方案,至少是因为可空类型带有较小的运行时开销,并且由于空合并运算符,对取消令牌的引用变得更加冗长??


11

另一种选择是使用Nullable<CancellationToken>参数,将其默认设置为null,然后在方法内部进行处理:

Task<x> DoStuff(...., CancellationToken? ct = null) {
    var token = ct ?? CancellationToken.None;
    ...
}

辉煌!到目前为止,这是最好的答案
John Henckel

4

较新版本的C#允许使用默认(CancellationToken)版本的简化语法。例如:

Task<x> DoStuff(...., CancellationToken ct = default)

-1

Tofutim的回答是一种方法,但是从评论中我看到人们对此有疑问

在这种情况下,我确实建议人们可以采用以下方法:

Task<x> DoStuff(...., CancellationToken ct)
{
} 

并将其重载为:

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}

之所以进行编译,是因为CancellationToken.None在编译时不需要的值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.