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.