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 ??.
new CancellationToken()which is exactly equivalent todefaultas CancellationToken is a struct.CancelationTokeneven if you have it in the calling method, on the other hand it is not that hard to typeCancellationToken.Nonein case you dont have it?