【问题标题】:Default parameter for CancellationTokenCancellationToken 的默认参数
【发布时间】:2014-03-12 17:45:52
【问题描述】:

我有一些异步代码,我想添加一个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 是一个结构体。

标签: c# asynchronous task-parallel-library cancellation-token


【解决方案1】:

事实证明,以下工作:

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 内部的内容,但我不会在我的代码中这样做。想想如果微软改变他们的实现,你的代码会发生什么,CancellationToken.None 变得比default(CancellationToken) 更多。
  • @Noseratio 这会在很大程度上破坏向后兼容性,所以我不希望发生这种情况。 default(CancellationToken) 还能做什么?
  • @Noseratio:你太死板了。 CancellationToken.None 很有可能实际上已被弃用。甚至微软也在使用default(CancellationToken)。例如,参见 Entity Framework 源代码中的these search results。
  • 来自 MSDN CancellationToken.None Property:“您还可以使用 C# default(CancellationToken) 语句创建一个空的取消令牌”。在 C# 的未来版本接受它作为默认参数之前,没有一个错误。
  • Same here 为了弥补两个缺失的中间组合,开发者可以为 cancelToken 参数传递 None 或默认的 CancellationToken,为 progress 参数传递 null。
【解决方案2】:

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

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

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

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

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

【讨论】:

【解决方案3】:

这里有几个解决方案,按一般优点的降序排列:

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

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

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

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

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

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

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

【讨论】:

    【解决方案4】:

    另一种选择是使用Nullable&lt;CancellationToken&gt;参数,默认为null,并在方法内部处理:

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

    【讨论】:

    • 太棒了!到目前为止,这是最好的答案
    【解决方案5】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-14
      • 2016-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-07
      • 1970-01-01
      • 2017-10-13
      相关资源
      最近更新 更多