183

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?

2
  • 1
    I've also seen new CancellationToken() which is exactly equivalent to default as CancellationToken is a struct. Commented May 13, 2021 at 11:27
  • 2
    Why would anybody want this? it is easy to forget to pass CancelationToken even if you have it in the calling method, on the other hand it is not that hard to type CancellationToken.None in case you dont have it? Commented Jun 9, 2023 at 9:36

5 Answers 5

273

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.

Sign up to request clarification or add additional context in comments.

8 Comments

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).
@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: 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.
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.
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.
|
32

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 ??.

Comments

26

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); } 

3 Comments

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).
CancellationToken.None == default true
What's the matter with CancellationToken cancellationToken = default(CancellationToken)? Also described here blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…
12

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

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

Comments

11

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; ... } 

3 Comments

brilliant! by far this is the best answer
This is the same as providing default now c# 7.1 above. It's better to just use default.
I have been using '''null''' with the latest .Net 8 until I updated my packages today (in a MAUI project). Suddenly I got the error message "cannot convert from '<null>' to 'System.Threading.CancellationToken'". I changed it to '''default''' and it runs now.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.