我试图让C#中的任务适用于特定用例,但我不理解任务延续选项如何影响任务流。
我尝试做的是将一系列任务与ContinueWith链接在一起。这看起来像这样:
A - > B - > C - > d
但是,我想在错误发生时包含短路选项,所以看起来应该是这样的:
A - > B - > C - > D - > X
所以我把" OnlyOnRanToCompletion"作为每个ContinueWith函数的任务延续选项。然后,为了捕获取消并返回错误,我将最终任务放在链的末尾,并将任务继续选项设置为" OnlyOnCanceled"。
问题在于,当命中最后一个块时,不满足继续选项,然后即使原始系列任务从未被取消,任务也会被设置为取消。
我想要发生的是A到D跑,如果其中一个导致取消,跳过其余的并运行X.如果A到D完成,任务不应该取消。该解决方案需要支持任意数量的continuation,并且将使用LINQ.Expressions创建,因此使用async / await可能不会成功,除非它创造性地完成。
展示这一点的一些示例代码是:
var cts = new CancellationTokenSource();
var token = cts.Token;
var t = Task.FromResult(1)
.ContinueWith(
x => x.Result + 1,
token,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default)
.ContinueWith(
x => x.Result + 1,
token,
TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default)
.ContinueWith(
x => -1,
token,
TaskContinuationOptions.OnlyOnCanceled,
TaskScheduler.Default);
此处的预期行为是返回3,状态未完成。
实际结果是任务被取消。
我该怎么做?
另外,我不能使用async
,因为我的目标是在LINQ.Expressions编译的内容中捎带TPL,以便它可以异步评估并在最后处理错误而不会抛出任何异常。
答案 0 :(得分:1)
想出来 - 无论前面的延续是否完成而没有将状态设置为取消,最后一次继续运行都是这样做的:
将最后一个延续的继续选项更改为TaskContinuation.None
,以便它始终运行,因此如果状态为已完成,则不会取消。
不要将取消令牌传递给最后一个延续,因为传入已取消的取消令牌似乎会导致取消继续取消,如果它没有令牌就会运行
答案 1 :(得分:0)
有关此行为的说明,请参阅ContinueWith
的备注:
在当前任务完成之前,不会安排返回的任务执行。如果不满足通过continuationOptions参数指定的条件,则将取消继续任务而不是已安排。
由于未达到上次ContinueWith
来电的条件,因此该通话返回的Task
已取消。