Parametro predefinito per CancellationToken


96

Ho un codice asincrono a cui vorrei aggiungere un file CancellationToken. Tuttavia, ci sono molte implementazioni in cui questo non è necessario, quindi mi piacerebbe avere un parametro predefinito, forse CancellationToken.None. Però,

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

rendimenti

Un valore di tipo "" non può essere utilizzato come parametro predefinito perché non esistono conversioni standard per il tipo "System.Threading.CancellationToken"

e

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

Il valore del parametro predefinito per "ct" deve essere una costante del tempo di compilazione

C'è un modo per avere un valore predefinito per CancellationToken?

Risposte:


151

Si scopre che funziona quanto segue:

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

che, secondo la documentazione , è interpretato come CancellationToken.None:

È anche possibile usare l' default(CancellationToken)istruzione C # per creare un token di annullamento vuoto.


4
Questo è esattamente ciò che il framework attualmente fa internamente, ma non lo farei nel mio codice. Pensa a cosa succede con il tuo codice se Microsoft cambia la loro implementazione e CancellationToken.Nonediventa qualcosa di più default(CancellationToken).
— noseratio

10
@Noseratio Ciò interromperà la compatibilità con le versioni precedenti in grande stile, quindi non mi aspetto che ciò accada. E cos'altro farebbe default(CancellationToken)?
— svick

3
@Noseratio: sei troppo rigido. È probabile CancellationToken.Noneche diventerà de facto deprecato. Anche Microsoft sta usando default(CancellationToken)invece. Ad esempio, vedere questi risultati della ricerca dal codice sorgente di Entity Framework.
— drowa

21
Dalla proprietà CancellationToken.None di MSDN : "È inoltre possibile utilizzare l'istruzione predefinita C # (CancellationToken) per creare un token di annullamento vuoto" . Nessuno è un errore finché una versione futur di C # non lo accetta come parametro predefinito.
— MuiBienCarlota

5
Stessa cosa qui Per compensare le due combinazioni intermedie mancanti, gli sviluppatori possono passare None o un CancellationToken predefinito per il parametro cancelToken e null per il parametro progress.
— Arek Bal

25

C'è un modo per avere un valore predefinito per CancellationToken?

Sfortunatamente, ciò non è possibile, poiché CancellationToken.Nonenon è una costante del tempo di compilazione, che è un requisito per i valori predefiniti negli argomenti opzionali.

È possibile fornire lo stesso effetto, tuttavia, creando un metodo sovraccarico invece di provare a utilizzare i parametri predefiniti:

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

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

6
Questo è il modo consigliato per gestirlo, come spiegato nella documentazione del modello asincrono basato su attività su MSDN (in particolare nella sezione Scelta degli sovraccarichi da fornire ).
— Sam Harwell

CancellazioneToken.None == default true
— eoleary

5
Qual è il problema CancellationToken cancellationToken = default(CancellationToken)? Descritto anche qui blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…
— Ray

20

Ecco diverse soluzioni, in ordine decrescente di bontà generale:

1. Utilizzo default(CancellationToken)come valore predefinito:

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

Semanticamente, CancellationToken.Nonesarebbe il candidato ideale per l'impostazione predefinita, ma non può essere utilizzato come tale perché non è una costante del tempo di compilazione. default(CancellationToken)è la prossima cosa migliore perché è una costante del tempo di compilazione e ufficialmente documentata per essere equivalente aCancellationToken.None .

2. Fornire un sovraccarico del metodo senza un CancellationTokenparametro:

Oppure, se preferisci gli overload del metodo rispetto ai parametri opzionali (vedi questa e questa domanda su quell'argomento):

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

Per i metodi di interfaccia, lo stesso può essere ottenuto utilizzando metodi di estensione:

interface IFoo
{
    Task DoAsync(CancellationToken ct);
}

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

Ciò si traduce in un'interfaccia più snella e si evita agli implementatori di scrivere esplicitamente il sovraccarico del metodo di inoltro.

3. Rendendo il parametro nullable e utilizzando nullcome valore predefinito:

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

Mi piace questa soluzione almeno perché i tipi nullable hanno un piccolo overhead di runtime ei riferimenti al token di annullamento diventano più dettagliati a causa dell'operatore di coalescenza null ??.


11

Un'altra opzione è usare un Nullable<CancellationToken>parametro, impostarlo come predefinito nulle gestirlo all'interno del metodo:

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

brillante! di gran lunga questa è la risposta migliore
— John Henckel

4

Le versioni più recenti di C # consentono una sintassi semplificata per la versione predefinita (CancellationToken). Per esempio:

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

-1

La risposta di Tofutim è unidirezionale, ma dai commenti vedo che le persone hanno problemi con essa.

In quel caso, ho suggerito che si può avere un metodo come segue:

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

e sovraccaricarlo come:

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

Questo compila, perché il valore di CancellationToken.Nonenon è richiesto in fase di compilazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.