C# 如何在不触发取消本身的情况下处理已取消的任务?

C# 如何在不触发取消本身的情况下处理已取消的任务?,c#,task-parallel-library,C#,Task Parallel Library,我试图让C#中的任务为特定用例工作,但我不理解任务延续选项如何影响任务流 我想做的是用ContinueWith将一系列任务链接在一起。这将看起来像这样: A->B->C->D 但是,我想包括在发生错误时使其短路的选项,因此它应该如下所示: A->B->C->D->X 所以我把“OnlyOnRanToCompletion”作为每个ContinueWith函数的任务延续选项。然后,为了捕获取消并返回错误,我将最后一个任务放在链的末尾,任务继续选项设置为“onlyoncancelled” 问题是,当命

我试图让C#中的任务为特定用例工作,但我不理解任务延续选项如何影响任务流

我想做的是用ContinueWith将一系列任务链接在一起。这将看起来像这样:

A->B->C->D

但是,我想包括在发生错误时使其短路的选项,因此它应该如下所示:

A->B->C->D->X

所以我把“OnlyOnRanToCompletion”作为每个ContinueWith函数的任务延续选项。然后,为了捕获取消并返回错误,我将最后一个任务放在链的末尾,任务继续选项设置为“onlyoncancelled”

问题是,当命中最后一个块时,不满足“继续”选项,并且即使原始任务系列从未取消,任务也会被设置为“取消”

我想做的是运行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,状态为not completed

实际结果是任务被取消

我该怎么做


另外,我不能使用
async
,因为我的目标是在从LINQ.Expressions编译的内容中使用TPL,这样它就可以异步计算并在结束时处理错误,而不会引发任何异常。

有关此行为的解释,请参阅
ContinueWith
的备注:

在当前任务完成之前,不会计划执行返回的任务。如果不满足通过continuationOptions参数指定的条件,则将取消继续任务而不是计划任务


由于未满足上次调用<代码>继续的条件,因此从该调用返回的<代码>任务<代码>被取消。

解决了这个问题-要让上次继续运行,无论以前的继续是否已完成,并且不将状态设置为已取消,请执行以下操作:

  • 将最后一个延续的延续选项更改为
    TaskContinuation.None
    ,这样它将始终运行,因此如果它以完成状态到达此处,它将不会取消

  • 不要将取消令牌传递给上一个延续,因为如果延续在没有令牌的情况下运行,则传递已取消的取消令牌似乎会导致延续取消


  • 您应该真正使用
    await
    ,而不是
    ContinueWIth
    来构建异步工作流<代码>等待更易于使用,并且在许多领域都有更理想的默认行为,特别是在错误处理方面,正如您在这里看到的。我应该将此添加到问题中-如果我能够,我会,但我不能。我正在使用LINQ.Expressions编译一个需要异步运行的小程序,我没有访问权限。我强烈怀疑这一点,但如果您不打算提供有关实际问题的足够信息,那么人们就不能给你一个好的解决方案了。这是真的:通过一个命名的异步方法和一个简单调用它的lambda,这个问题很容易就被解决了。再说一次,如果你不描述你的实际问题,那么你就无法得到很好的解决方案。