web-dev-qa-db-fra.com

Paramètre par défaut pour CancellationToken

J'ai du code asynchrone auquel j'aimerais ajouter un CancellationToken. Cependant, il existe de nombreuses implémentations où cela n'est pas nécessaire, donc je voudrais avoir un paramètre par défaut - peut-être CancellationToken.None. cependant,

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

les rendements

Une valeur de type "" ne peut pas être utilisée comme paramètre par défaut car il n'y a pas de conversions standard pour taper "System.Threading.CancellationToken"

et

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

La valeur de paramètre par défaut pour 'ct' doit être une constante de temps de compilation

Existe-t-il un moyen d'avoir une valeur par défaut pour CancellationToken?

71
tofutim

Il s'avère que les travaux suivants:

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

qui, selon la documentation , est interprété de la même façon que CancellationToken.None:

Vous pouvez également utiliser l'instruction C # default(CancellationToken) pour créer un jeton d'annulation vide.

107
tofutim

Existe-t-il un moyen d'avoir une valeur par défaut pour CancellationToken?

Malheureusement, ce n'est pas possible, car CancellationToken.None n'est pas une constante de temps de compilation, ce qui est une exigence pour les valeurs par défaut dans les arguments facultatifs.

Vous pouvez cependant fournir le même effet en créant une méthode surchargée au lieu d'essayer d'utiliser les paramètres par défaut:

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

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

Voici plusieurs solutions, par ordre décroissant de bonté générale:

1. Utilisation de default(CancellationToken) comme valeur par défaut:

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

Sémantiquement, CancellationToken.None Serait le candidat idéal pour la valeur par défaut, mais ne peut pas être utilisé tel quel car il ne s'agit pas d'une constante de temps de compilation. default(CancellationToken) est la prochaine meilleure chose car c'est une constante de temps de compilation et officiellement documenté pour être équivalent à CancellationToken.None .

2. Fournir une surcharge de méthode sans paramètre CancellationToken:

Ou, si vous préférez les surcharges de méthode aux paramètres facultatifs (voir this et this question sur ce sujet):

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

Pour les méthodes d'interface, la même chose peut être obtenue en utilisant des méthodes d'extension:

interface IFoo
{
    Task DoAsync(CancellationToken ct);
}

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

Cela se traduit par une interface plus mince et évite aux implémenteurs d'écrire explicitement la surcharge de la méthode de transfert.

3. Rendre le paramètre nullable et utiliser null comme valeur par défaut:

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

J'aime moins cette solution car les types nullables sont livrés avec une petite surcharge d'exécution et les références au jeton d'annulation deviennent plus verbeuses en raison de l'opérateur de coalescence nul ??.

18
stakx

Une autre option consiste à utiliser un Nullable<CancellationToken> paramètre, définissez-le par défaut sur null, et traitez-le dans la méthode:

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