ChatGPT解决这个技术问题 Extra ChatGPT

CancellationToken 的默认参数

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

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

产量

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

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

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

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

我还看到 new CancellationToken()default 完全相同,因为 CancellationToken 是一个结构。

T
Theodor Zoulias

事实证明,以下工作:

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

...或者:

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

其中 according to the documentation 的解释与 CancellationToken.None 相同:

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


这正是 framework currently does 内部的内容,但我不会在我的代码中这样做。想一想如果 Microsoft 更改其实现,您的代码会发生什么情况,并且 CancellationToken.None 不仅仅是 default(CancellationToken)
@Noseratio 这会在很大程度上破坏向后兼容性,所以我不希望发生这种情况。 default(CancellationToken) 还会做什么?
@Noseratio:你太死板了。很有可能 CancellationToken.None 将成为事实上的弃用。甚至 Microsoft 也在使用 default(CancellationToken)。例如,参见 Entity Framework 源代码中的 these search results
来自 MSDN CancellationToken.None Property“您还可以使用 C# default(CancellationToken) 语句创建一个空的取消令牌”。在未来版本的 C# 接受它作为默认参数之前,None 是一个错误。
相同的 here 为了弥补两个缺失的中间组合,开发人员可以为 cancelToken 参数传递 None 或默认的 CancellationToken,为 progress 参数传递 null。
R
Reed Copsey

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

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

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

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

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

这是处理此问题的推荐方法,如 MSDN 上的 Task-based Asynchronous Pattern 文档中所述(特别是在选择要提供的重载部分)。
CancellationToken.None == 默认为真
CancellationToken cancellationToken = default(CancellationToken) 怎么了?此处也有描述blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…
C
Community

以下是几种解决方案,按一般优点的降序排列:

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

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

从语义上讲,CancellationToken.None 将是默认值的理想候选者,但不能这样使用,因为它不是编译时常量。 default(CancellationToken) 是次优的,因为它是编译时常量和 officially documented to be equivalent to CancellationToken.None

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

或者,如果您更喜欢方法重载而不是可选参数(请参阅关于该主题的 thisthis 问题):

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

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


T
Todd Menier

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

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

杰出的!到目前为止,这是最好的答案
A
Alexei - check Codidact

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

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