Standardparameter für CancellationToken

96

Ich habe einen asynchronen Code, zu dem ich einen hinzufügen möchte CancellationToken. Es gibt jedoch viele Implementierungen, bei denen dies nicht erforderlich ist, sodass ich einen Standardparameter haben möchte - vielleicht CancellationToken.None. Jedoch,

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

ergibt

Ein Wert vom Typ '' kann nicht als Standardparameter verwendet werden, da keine Standardkonvertierungen für den Typ 'System.Threading.CancellationToken' vorhanden sind.

und

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

Der Standardparameterwert für 'ct' muss eine Konstante zur Kompilierungszeit sein

Gibt es eine Möglichkeit, einen Standardwert für CancellationTokenfestzulegen?

tofutim
quelle

Antworten:

151

Es stellt sich heraus, dass Folgendes funktioniert:

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

was laut Dokumentation wie folgt interpretiert wird CancellationToken.None:

Sie können auch die C # default(CancellationToken)-Anweisung verwenden, um ein leeres Stornierungs-Token zu erstellen.

tofutim
quelle
4
Dies ist genau das, was das Framework derzeit intern tut , aber ich würde es in meinem Code nicht tun. Überlegen Sie, was mit Ihrem Code passiert, wenn Microsoft die Implementierung ändert und CancellationToken.Noneetwas mehr als wird default(CancellationToken).
Noseratio
10
@Noseratio Das würde die Abwärtskompatibilität stark beeinträchtigen, daher würde ich nicht erwarten, dass dies passiert. Und was würde sonst noch default(CancellationToken)tun?
Svick
3
@Noseratio: Du bist zu starr. Die Chancen stehen gut, CancellationToken.Nonedass sie de facto veraltet sind. Sogar Microsoft verwendet default(CancellationToken)stattdessen. Sehen Sie sich beispielsweise diese Suchergebnisse aus dem Quellcode des Entity Framework an.
Drowa
21
Von MSDN CancellationToken.None-Eigenschaft : "Sie können auch die C # -Standardanweisung (CancellationToken) verwenden, um ein leeres Stornierungs-Token zu erstellen . " Keiner ist ein Fehler, bis eine zukünftige Version von C # ihn als Standardparameter akzeptiert.
MuiBienCarlota
5
Gleiches hier Um die beiden fehlenden Zwischenkombinationen zu kompensieren, können Entwickler None oder ein Standard-CancellationToken für den Parameter cancellationToken und null für den Parameter progress übergeben.
Arek Bal
25

Gibt es eine Möglichkeit, einen Standardwert für CancellationToken festzulegen?

Dies ist leider nicht möglich, da CancellationToken.Nonees sich nicht um eine Kompilierungszeitkonstante handelt, die für Standardwerte in optionalen Argumenten erforderlich ist.

Sie können den gleichen Effekt erzielen, indem Sie eine überladene Methode erstellen, anstatt zu versuchen, Standardparameter zu verwenden:

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

Task<x> DoStuff(....)
{
    return DoStuff(...., CancellationToken.None);
}
Reed Copsey
quelle
6
Dies ist die empfohlene Vorgehensweise, wie in der Dokumentation zu aufgabenbasierten asynchronen Mustern in MSDN erläutert (insbesondere im Abschnitt Auswählen der anzuwendenden Überlastungen ).
Sam Harwell
CancellationToken.None == default true
eoleary
5
Was ist los mit CancellationToken cancellationToken = default(CancellationToken)? Auch hier beschrieben blogs.msdn.microsoft.com/andrewarnottms/2014/03/19/…
Ray
20

Hier sind mehrere Lösungen in absteigender Reihenfolge der allgemeinen Güte:

1. default(CancellationToken)Als Standardwert verwenden:

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

Semantisch CancellationToken.Nonewäre dies der ideale Kandidat für die Standardeinstellung, kann jedoch nicht als solcher verwendet werden, da es sich nicht um eine Konstante für die Kompilierungszeit handelt. default(CancellationToken)ist das nächstbeste, da es sich um eine Konstante zur Kompilierungszeit handelt, die offiziell als gleichwertig dokumentiert istCancellationToken.None .

2. Bereitstellung einer Methodenüberladung ohne CancellationTokenParameter:

Oder wenn Sie Methodenüberladungen gegenüber optionalen Parametern bevorzugen (siehe diese und diese Frage zu diesem Thema):

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

Für Schnittstellenmethoden kann dasselbe mit Erweiterungsmethoden erreicht werden:

interface IFoo
{
    Task DoAsync(CancellationToken ct);
}

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

Dies führt zu einer schlankeren Benutzeroberfläche und erspart Implementierern das explizite Schreiben der Überladung der Weiterleitungsmethode.

3. Den Parameter auf Null setzen und nullals Standardwert verwenden:

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

Diese Lösung gefällt mir am wenigsten, weil nullfähige Typen mit einem geringen Laufzeitaufwand verbunden sind und Verweise auf das Lösch-Token aufgrund des Null-Koaleszenz-Operators ausführlicher werden ??.

stakx - nicht mehr beitragen
quelle
11

Eine andere Möglichkeit besteht darin, einen Nullable<CancellationToken>Parameter zu verwenden, ihn standardmäßig zu verwenden nullund ihn innerhalb der Methode zu behandeln:

Task<x> DoStuff(...., CancellationToken? ct = null) {
    var token = ct ?? CancellationToken.None;
    ...
}
Todd Menier
quelle
brillant! bei weitem das ist die beste Antwort
John Henckel
4

Neuere Versionen von C # ermöglichen eine vereinfachte Syntax für die Standardversion (CancellationToken). Z.B:

Task<x> DoStuff(...., CancellationToken ct = default)
Alexei
quelle
-1

Tofutims Antwort ist eine Möglichkeit, aber aus den Kommentaren geht hervor, dass die Leute Probleme damit haben.

In diesem Fall habe ich vorgeschlagen, dass man eine Methode wie folgt haben kann:

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

und überladen Sie es als:

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

Dies wird kompiliert, da der Wert von CancellationToken.Nonezur Kompilierungszeit nicht erforderlich ist.

Ozair Kafray
quelle