CancellationToken的默认参数

tof*_*tim 76 c# asynchronous task-parallel-library cancellation-token

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

Task<x> DoStuff(...., CancellationToken ct = null)
Run Code Online (Sandbox Code Playgroud)

产量

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

Task<x> DoStuff(...., CancellationToken ct = CancellationToken.None)
Run Code Online (Sandbox Code Playgroud)

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

有没有办法让CancellationToken有一个默认值?

tof*_*tim 115

事实证明,以下工作:

Task<x> DoStuff(...., CancellationToken ct = default(CancellationToken))
Run Code Online (Sandbox Code Playgroud)

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

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

  • 来自MSDN [CancellationToken.None Property](https://msdn.microsoft.com/en-us/library/dd780763(v = vs.110).aspx):_"您还可以使用C#默认(CancellationToken)语句创建一个空取消令牌"_.在未来版本的C#接受默认参数之前,没有错误. (21认同)
  • @Noseratio这会大大破坏向后兼容性,所以我不希望这种情况发生.还有什么呢?默认(CancellationToken)`做什么? (8认同)
  • 相同[这里](https://msdn.microsoft.com/en-us/library/hh873175.aspx)_为了弥补两个缺少的中间组合,开发人员可以为cancelToken参数传递None或默认的CancellationToken,并为进度参数._ (5认同)
  • 这正是内部的[框架*当前*所做的](http://referencesource.microsoft.com/#mscorlib/system/threading/CancellationToken.cs#ec32c41597007382),但我不会*在我的代码中执行此操作.想想如果微软改变他们的实现你的代码会发生什么,并且`CancellationToken.None`变得超过`default(CancellationToken)`. (4认同)
  • @Noseratio:你太死板了。可能是`CancellationToken.None`实际上将被弃用。甚至Microsoft都使用`default(CancellationToken)`。例如,从实体框架的源代码中查看[这些搜索结果](https://github.com/aspnet/EntityFramework/search?q=default%28CancellationToken%29)。 (3认同)

Ree*_*sey 22

有没有办法让CancellationToken有一个默认值?

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

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

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

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}
Run Code Online (Sandbox Code Playgroud)

  • 这是处理此问题的推荐方法,如MSDN上的[基于任务的异步模式](http://msdn.microsoft.com/en-us/library/hh873175.aspx)文档中所述(特别是在*部分中)*选择过载以提供**). (5认同)
  • `CancellationToken cancellingToken = default(CancellationToken)`有什么问题?在此处也描述了https://blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/recommended-patterns-for-cancellationtoken/ (4认同)

sta*_*ica 19

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

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

Task DoAsync(CancellationToken ct = default(CancellationToken)) { … }
Run Code Online (Sandbox Code Playgroud)

在语义上,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
Run Code Online (Sandbox Code Playgroud)

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

interface IFoo
{
    Task DoAsync(CancellationToken ct);
}

static class Foo
{
    public static Task DoAsync(this IFoo foo) => foo.DoAsync(CancellationToken.None);
}
Run Code Online (Sandbox Code Playgroud)

这导致更简洁的接口和备用实现者明确地编写转发方法重载.

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

Task DoAsync(…, CancellationToken? ct = null)
{
    … ct ?? CancellationToken.None …
}
Run Code Online (Sandbox Code Playgroud)

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


Tod*_*ier 11

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

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


Ale*_*xei 7

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

Task<x> DoStuff(...., CancellationToken ct = default)
Run Code Online (Sandbox Code Playgroud)