Frage

ich habe gelesen Die Natur von TaskCompletionSource, ein Beitrag von Stephen Toub.

public static Task RunAsync(Action action)
{
    var tcs = new TaskCompletionSource<Object>();
    ThreadPool.QueueUserWorkItem(_ =>
    {
        try
        {
            action();
            tcs.SetResult(null);
        }
        catch(Exception exc) { tcs.SetException(exc); }
    });
    return tcs.Task;
}

Da ist es uns egal, um welche Art es sich handelt T ist, dass ich standardmäßig verwendet habe Object.Dann, wenn die Action erfolgreich ausgeführt wird, SetResult wird immer noch zum Übergang verwendet Task in die RanToCompletion Endzustand;Da der tatsächliche Ergebniswert jedoch irrelevant ist, null wird eingesetzt. Endlich, RunAsync kehrt zurück Task statt Task<Object>.Natürlich das instanziierte taskDer Typ ist immer noch Task<Object>, aber wir müssen es nicht als solches bezeichnen, und der Verbraucher dieser Methode muss sich nicht um diese Implementierungsdetails kümmern.

Ich verstehe nicht besonders, warum die Methode zurückkehren sollte Task statt Task<object> (weshalb ich den fettgedruckten Satz hervorgehoben habe).Ich weiß, dass die Methode auf Rückkehr eingestellt ist Task Aber tcs ist ein TaskCompletionSource<Object>, nicht TaskCompletionSource (was meiner Meinung nach falsch ist).

War es hilfreich?

Lösung

Es gibt kein Nicht-Generikum TaskCompletionSource Und wenn man bedenkt, dass alles, was Sie wollen, eine Aufgabe ohne Ergebnis ist, spielt das Ergebnis keine Rolle.Der Anrufer weiß nicht und kümmert sich in diesem Fall nicht darum, dass es sich bei der Aufgabe tatsächlich um eine handelt Task<object>, Der Anrufer gerade awaits es, und bekommt eine Ausnahme, wenn es eine gibt.Der Anrufer erfährt vom tatsächlichen Ergebnis nichts.

Dies wird natürlich dadurch erleichtert Task<T> erbt von Task


Es ist auch üblich, eine zu finden Task<bool> das gibt false zurück, oder Task<int> mit 0.

Andere Tipps

Es gibt kein Nicht-Generikum TaskCompletionSource Klasse zum Erstellen von Instanzen von Task die keine Beispiele dafür sind Task<T>.Dadurch bleiben zwei Optionen für den generischen Typparameter für übrig TaskCompletionSource<T> wenn Ihnen der Rückgabewert egal ist (oder Sie ihn nicht angeben):

  1. Verwenden Sie einen beliebigen vorhandenen Typ, z object, als Rückgabetyp.Stellen Sie den Wert auf ein null um den Abschluss der Aufgabe anzuzeigen.
  2. Verwenden Sie einen bestimmten nicht öffentlichen Typ und legen Sie den Wert auf fest null um den Abschluss der Aufgabe anzuzeigen.

Wenn ich ein erstelle TaskCompletionSource<T> zum Beispiel zum Zweck der Bereitstellung von a Task Ohne Rückgabewert bevorzuge ich die Verwendung eines dedizierten, nicht öffentlichen Typs, um sicherzustellen, dass der zurückgegebene Code beim Konsumieren nicht verwechselt wird Task als Beispiel für Task<T> wo das Ergebnis eine Bedeutung hat.

Zuerst definiere ich die folgende Klasse (es kann eine sein private sealed class wenn es in einem anderen Typ verschachtelt ist):

internal sealed class VoidResult
{
}

Dann, anstatt zu verwenden TaskCompletionSource<object> Als Vervollständigungsquelle verwende ich TaskCompletionSource<VoidResult>.Seit der VoidResult Auf den Typ kann durch Aufrufen des Codes nicht zugegriffen werden. Der Benutzer kann ihn nicht umwandeln Task Objekt einer Instanz von Task<VoidResult>.

Ich verstehe nicht besonders, warum die Methode zurückkehren sollte Task statt Task<object>

Denn wenn du zurückkommst Task<Object> Dies bedeutet, dass diese Methode nach Abschluss einen nützlichen Typwert erzeugt Object.In diesem Fall erzielen wir kein Ergebnis. Deshalb hat sich Stephen für die Rückkehr entschieden Task.

Wenn wir uns damit befassen Func<Object> dann zurück Task<Object> wäre angebracht, als Func zu einem Ergebnis führen wird, können wir uns dafür entscheiden, es zurückzugeben.

Warum TaskCompletionSource<Object>, nicht TaskCompletionSource?

Weil es so etwas nicht gibt.Es gibt kein Nicht-Generikum TaskCompletionSource.

Wenn Sie a zurückgegeben haben Task<object>, Dann var result = await RunAsync(...) würde immer wiederkommen null, da Sie das Ergebnis darauf einstellen.

Dem Kunden ist das egal, also geben Sie einfach eine zurück Task.

Idealerweise verwenden Sie a TaskCompletionSource intern, statt a TaskCompletionSource<object>, und rufen Sie einfach so etwas wie SetCompleted() anstatt SetResult(null).Aber einen solchen Typ gibt es nicht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top