Default parameter for CancellationToken

53,638

Solution 1

It turns out that the following works:

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

...or:

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

which, according to the documentation, is interpreted the same as CancellationToken.None:

You can also use the C# default(CancellationToken) statement to create an empty cancellation token.

Solution 2

Is there any way to have a default value for CancellationToken?

Unfortunately, this is not possible, as CancellationToken.None is not a compile time constant, which is a requirement for default values in optional arguments.

You can provide the same effect, however, by making an overloaded method instead of trying to use default parameters:

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

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

Solution 3

Here are several solutions, in descending order of general goodness:

1. Using default(CancellationToken) as default value:

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

Semantically, CancellationToken.None would be the ideal candidate for the default, but cannot be used as such because it isn't a compile-time constant. default(CancellationToken) is the next best thing because it is a compile-time constant and officially documented to be equivalent to CancellationToken.None.

2. Providing a method overload without a CancellationToken parameter:

Or, if you prefer method overloads over optional parameters (see this and this question on that topic):

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

For interface methods, the same can be achieved using extension methods:

interface IFoo
{
    Task DoAsync(CancellationToken ct);
}

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

This results in a slimmer interface and spares implementers from explicitly writing the forwarding method overload.

3. Making the parameter nullable and using null as default value:

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

I like this solution least because nullable types come with a small runtime overhead, and references to the cancellation token become more verbose because of the null coalescing operator ??.

Solution 4

Another option is to use a Nullable<CancellationToken> parameter, default it to null, and deal with it inside the method:

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

Solution 5

Newer versions of C# allow for a simplified syntax for the default(CancellationToken) version. E.g.:

Task<x> DoStuff(...., CancellationToken ct = default)
Share:
53,638
tofutim
Author by

tofutim

Updated on August 23, 2022

Comments

  • tofutim
    tofutim over 1 year

    I have some async code that I would like to add a CancellationToken to. However, there are many implementations where this is not needed so I would like to have a default parameter - perhaps CancellationToken.None. However,

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

    yields

    A value of type '<null>' cannot be used as a default parameter because there are no standard conversions to type 'System.Threading.CancellationToken'

    and

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

    Default parameter value for 'ct' must be a compile-time constant

    Is there any way to have a default value for CancellationToken?

    • Palec
      Palec almost 3 years
      I've also seen new CancellationToken() which is exactly equivalent to default as CancellationToken is a struct.
  • Sam Harwell
    Sam Harwell about 10 years
    This is the recommended way to handle this, as explained on the Task-based Asynchronous Pattern documentation on MSDN (specifically in the section Choosing the Overloads to Provide).
  • noseratio
    noseratio about 10 years
    This is exactly what the framework currently does internally, but I would not do it in my code. Think what happens with your code if Microsoft change their implementation, and CancellationToken.None becomes something more than default(CancellationToken).
  • svick
    svick about 10 years
    @Noseratio That would break backwards compatibility in a big way, so I wouldn't expect that to happen. And what else would default(CancellationToken) do?
  • noseratio
    noseratio about 10 years
    @svick, if my library references System.Threading.CancellationToken.None property, and the value of CancellationToken.None changes in a future version of mscorlib.dll, how would that break my library (the IL code)? I would not make predictions about default(CancellationToken) though.
  • svick
    svick about 10 years
    @Noseratio If your library uses default(CancellationToken) (or new CancellationToken()), which I think is a valid thing to do for any value type, and that value started behaving differently, then that would break compatibility.
  • noseratio
    noseratio about 10 years
    @svick, I see your point, but nowhere on MSDN it is mentioned that CancellationToken.None is the same thing as default(CancellationToken). Technically it may become a static readonly struct with non-default fields, unlikely but possible. Then if my library used CancellationToken.None, I'd stay compatible. Not so if it used default(CancellationToken).
  • drowa
    drowa about 9 years
    @Noseratio: You're being too rigid. Chances are CancellationToken.None will become de facto deprecated. Even Microsoft is using default(CancellationToken) instead. For example, see these search results from the source code of the Entity Framework.
  • noseratio
    noseratio about 9 years
    @drowa, peace here. CancellationToken.None is unlikely to be deprecated, but I've been using myself default(CancellationToken) since then :) Plus to the OP.
  • MuiBienCarlota
    MuiBienCarlota almost 9 years
    From MSDN CancellationToken.None Property: "You can also use the C# default(CancellationToken) statement to create an empty cancellation token". None is a mistake until a futur version of C# accept it as default parameter.
  • Arek Bal
    Arek Bal over 8 years
    Same here To compensate for the two missing intermediate combinations, developers may pass None or a default CancellationToken for the cancellationToken parameter and null for the progress parameter.
  • eoleary
    eoleary about 6 years
    CancellationToken.None == default true
  • Syroot
    Syroot about 6 years
    What's the matter with CancellationToken cancellationToken = default(CancellationToken)? Also described here blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…
  • John Henckel
    John Henckel almost 5 years
    brilliant! by far this is the best answer