ChatGPT解决这个技术问题 Extra ChatGPT

Default parameter for CancellationToken

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

I've also seen new CancellationToken() which is exactly equivalent to default as CancellationToken is a struct.

T
Theodor Zoulias

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.


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.
R
Reed Copsey

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

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/…
C
Community

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


T
Todd Menier

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

brilliant! by far this is the best answer
A
Alexei - check Codidact

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

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