取消令牌的默认参数

我有一些异步代码,我想添加一个 CancellationToken。但是,有许多实现并不需要这个参数,所以我希望有一个默认参数-也许是 CancellationToken.None。但是,

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

产量

类型为“ < null >”的值不能用作默认参数,因为 没有到类型的标准转换 系统,线程,取消令牌

还有

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

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

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

63021 次浏览

有没有什么方法可以为 CancelationToken 设置默认值?

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

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

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


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

事实证明,以下方法是有效的:

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

或者:

Task<x> DoStuff(...., CancellationToken ct = default) // C# 7.1 and later

根据文件记录的解释与 CancellationToken.None相同:

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

另一种选择是使用 Nullable<CancellationToken>参数,将其默认为 null,并在方法内部处理它:

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

以下是一些解决方案,按照一般善良程度的递减顺序排列:

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 …
}

我最不喜欢这个解决方案,因为可空类型带来了小的运行时开销,并且由于空合并操作符 ??,对取消令牌的引用变得更加冗长。

较新的 C # 版本允许为默认版本(取消令牌)提供简化的语法。例如:

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