Erstellen Sie eine abgeschlossene Aufgabe <T>

125

Ich implementiere eine Methode Task<Result> StartSomeTask()und kenne das Ergebnis bereits vor dem Aufruf der Methode. Wie erstelle ich eine Aufgabe <T> , die bereits abgeschlossen ist?

Das mache ich gerade:

private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var task = new Task<Result>(() => theResult);
    task.RunSynchronously(CurrentThreadTaskScheduler.CurrentThread);
    return task;
}

Gibt es eine bessere Lösung?

dtb
quelle
6
Beachten Sie, dass die Antworten auf diese Frage auch zum Erstellen einer einfachen Aufgabe (kein <T>) geeignet sind, da Aufgabe <T> von Aufgabe erbt.
Tim Lovell-Smith
Beachten Sie, dass es heute ValueTaskfür abgeschlossene Aufgaben gibt (dh für Werte, die Sie bereits haben, sodass der Code im Wesentlichen synchron ist), wodurch Sie eine Zuordnung sparen.
Nawfal

Antworten:

111
private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var taskSource = new TaskCompletionSource<Result>();
    taskSource.SetResult(theResult);
    return taskSource.Task;
}
QrystaL
quelle
@ DanielLobo Sie könnten eine Antwort erhalten, wenn Sie erklären, was Ihr Einwand ist
user2023861
1
Sollte es nicht die unten stehende sein, die einfacher und mit viel mehr Stimmen ist? @ user2023861
Daniel Lobo
203

Beim Targeting von .NET 4.5 können Sie Folgendes verwenden Task.FromResult:

public static Task<TResult> FromResult<TResult>(TResult result);

Verwenden Sie zum Erstellen einer fehlgeschlagenen Aufgabe Folgendes Task.FromException:

public static Task FromException(Exception exception);
public static Task<TResult> FromException<TResult>(Exception exception);

.NET 4.6 fügt hinzu, Task.CompletedTaskwenn Sie eine nicht generische benötigen Task.

public static Task CompletedTask { get; }

Problemumgehungen für ältere Versionen von .NET:

  • Wenn Sie mit Async Targetting Pack (oder AsyncCTP) auf .NET 4.0 abzielen, können Sie TaskEx.FromResultstattdessen verwenden.

  • Um Taskvor .NET 4.6 nicht generisch zu werden, können Sie die Tatsache verwenden, die Task<T>von abgeleitet ist, Taskund einfach Task.FromResult<object>(null)oder aufrufen Task.FromResult(0).

CodesInChaos
quelle
13
Um eine nicht generische Aufgabe zurückzugeben, ist es besser, etwas wie Task.FromResult (0) zu verwenden. Die Verwendung von "null" als Parameter kann den Compiler verwirren, der den generischen Parameter nicht bestimmen kann.
Whyllee
Was ist mit Ausnahmen? Asynchrone Methoden werden in eine Zustandsmaschine kompiliert, die Ausnahmen abfängt und in der zurückgegebenen Task speichert. Dies geschieht sogar für Code, der vor dem ersten Warten ausgeführt wird. Die Methode, die Task.FromResult zurückgibt, kann Ausnahmen direkt auslösen.
Robert Važan
@ RobertVažan Ein interessanter Randfall. Wenn Sie Ihr bekanntes Ergebnis von einer Methode abrufen und diese Methode Ausnahmen auslöst, liegt möglicherweise ein Fehler vor, der behoben werden muss.
Gusdor
1
@ RobertVažan Sie können ganz einfach Ihre eigene FromExceptionMethode schreiben , die sich wie FromResulteine fehlerhafte Aufgabe verhält, aber stattdessen eine fehlerhafte Aufgabe darstellt. Eine solche Methode kann dies einfach für ihre Fehlerfälle zurückgeben, wenn es wichtig ist, dass die Ausnahme in der resultierenden Aufgabe dargestellt wird.
Servy
1
Task.FromException ist in .NET 4.5 nicht verfügbar ... Ich denke, es sollte angegeben werden.
STiLeTT
12

Für Aufgaben ohne Rückgabewert hat .NET 4.6 Task.CompletedTask hinzugefügt .

Es gibt eine Aufgabe zurück, die sich bereits in TaskStatus.RanToCompletion befindet. Wahrscheinlich wird jedes Mal dieselbe Instanz zurückgegeben, aber die Dokumentation warnt Sie davor, sich auf diese Tatsache zu verlassen.

Daryl
quelle
1

Wenn Sie Rx verwenden, ist Observable.Return (Ergebnis) .ToTask () eine Alternative.

Niall Connaughton
quelle
1

Wenn Sie Task.WhenAll ohne Parameter aufrufen, wird eine abgeschlossene Aufgabe zurückgegeben.

Task task = Task.WhenAll();
zumalifeguard
quelle
Während dies funktionieren wird, ist es eine obskure Problemumgehung, die die Leute beim Lesen des Codes verwirren könnte, da es impliziert, auf Aufgaben zu warten, die nicht existieren
Adrian Hristov