So wurde mir kürzlich gesagt, dass die Verwendung von .ContinueWith for Tasks nicht der richtige Weg ist, sie zu verwenden. Ich habe noch keine Beweise dafür im Internet gefunden, also werde ich euch fragen und sehen, wie die Antwort lautet. Hier ist ein Beispiel für die Verwendung von .ContinueWith:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});
}
Jetzt weiß ich, dass dies ein einfaches Beispiel ist und sehr schnell ausgeführt wird, aber nehmen Sie einfach an, dass jede Aufgabe einen längeren Vorgang ausführt. Mir wurde also gesagt, dass Sie in .ContinueWith prevTask.Wait () sagen müssen; Andernfalls können Sie arbeiten, bevor die vorherige Aufgabe abgeschlossen ist. Ist das überhaupt möglich? Ich ging davon aus, dass meine zweite und dritte Aufgabe erst ausgeführt wird, wenn die vorherige Aufgabe abgeschlossen ist.
Was mir gesagt wurde, wie man den Code schreibt:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 3");
});
}
quelle
Antworten:
Ehhh .... Ich denke, einigen der aktuellen Antworten fehlt etwas: Was passiert mit Ausnahmen?
Der einzige Grund, warum Sie
Wait
eine Fortsetzung aufrufen würden, wäre die Beobachtung einer möglichen Ausnahme vom Vorgänger in der Fortsetzung selbst. Die gleiche Beobachtung würde passieren, wenn SieResult
im Fall von aTask<T>
zugreifen und auch wenn Sie manuell auf dieException
Eigenschaft zugreifen. Ehrlich gesagt würde ich nicht anrufenWait
oder darauf zugreifen,Result
denn wenn es eine Ausnahme gibt, zahlen Sie den Preis für die erneute Erhöhung, was unnötigen Aufwand bedeutet. Stattdessen können Sie dieIsFaulted
Eigenschaft einfach aus dem Vorgänger abhakenTask
. Alternativ können Sie gegabelte Workflows erstellen, indem Sie mehrere Geschwisterfortsetzungen verketten, die nur aufgrund von Erfolg oder Misserfolg mitTaskContinuationOptions.OnlyOnRanToCompletion
und ausgelöst werdenTaskContinuationOptions.OnlyOnFaulted
.Jetzt ist es nicht erforderlich, die Ausnahme des Antezedens in der Fortsetzung zu beachten, aber Sie möchten möglicherweise nicht, dass Ihr Workflow fortgesetzt wird, wenn beispielsweise "Schritt 1" fehlgeschlagen ist. In diesem Fall: Wenn Sie
TaskContinuationOptions.NotOnFaulted
IhreContinueWith
Anrufe angeben, wird verhindert, dass die Fortsetzungslogik jemals ausgelöst wird.Denken Sie daran, dass die Person, die darauf wartet, dass dieser gesamte Workflow abgeschlossen wird, diejenige ist, die ihn beobachtet, wenn Ihre eigenen Fortsetzungen die Ausnahme nicht beachten. Entweder sind sie
Wait
imTask
Upstream oder sie haben ihre eigene Fortsetzung angepackt, um zu wissen, wann sie abgeschlossen ist. Wenn es das letztere ist, müsste ihre Fortsetzung die oben erwähnte Beobachtungslogik verwenden.quelle
TaskContinuationOptions
Sie verwenden es richtig.
Quelle: Task.ContinueWith-Methode (Aktion als MSDN)
prevTask.Wait()
JedenTask.ContinueWith
Aufruf aufrufen zu müssen, scheint eine seltsame Art zu sein, unnötige Logik zu wiederholen - dh etwas zu tun, um "super duper sicher" zu sein, weil man eigentlich nicht versteht, was ein bestimmtes Stück Code bewirkt. Als würde man nach einer Null suchen, nur um eine zu werfen,ArgumentNullException
wo sie sowieso geworfen worden wäre.Also, nein, wer auch immer dir gesagt hat, dass das falsch ist und wahrscheinlich nicht versteht, warum es
Task.ContinueWith
existiert.quelle
Wer hat dir das gesagt?
MSDN zitieren :
Was wäre der Zweck von Continue With, wenn nicht darauf gewartet würde, dass die vorherige Aufgabe abgeschlossen wird?
Sie können es sogar selbst testen:
quelle
Aus der MSDN auf
Task.Continuewith
Ich denke, dass die Art und Weise, wie Sie es im ersten Beispiel erwarten, die richtige ist.
quelle
Möglicherweise möchten Sie auch Task.Run anstelle von Task.Factory.StartNew verwenden.
Stephen Clearys Blog-Post und der von ihm referenzierte Stephen Toub- Post erklären die Unterschiede. In dieser Antwort gibt es auch eine Diskussion .
quelle
Mit Access machen
Task.Result
Sie tatsächlich eine ähnliche Logik wietask.wait
quelle
Ich werde wiederholen, was viele bereits gesprochen haben,
prevTask.Wait()
ist unnötig .Weitere Beispiele finden Sie unter Verketten von Aufgaben mithilfe von Fortsetzungsaufgaben. Ein weiterer Link von Microsoft enthält gute Beispiele.
quelle