【问题标题】:Why does ContinueWith pass the Task as the parameter为什么ContinueWith传Task作为参数
【发布时间】:2016-06-25 22:18:02
【问题描述】:

我有一个Task<T> t1。我想在t1 完成后运行另一个Task t2。我选择使用t1.ContinueWith方法。

void ThenFrob(Task<Frobber> t1) {
    t1.ContinueWith(frobber => frobber.Frob())
}

除此之外,我不能这样做,因为Task&lt;T&gt; 的Action 参数是传递给Task&lt;T&gt;,而不是T 本身。相反,我必须将传递给我的操作的参数的结果与它进行交互。

void ThenFrob(Task<Frobber> t1) {
    t1.ContinueWith(frobberTask => {
        var frobber = frobberTask.Result;
        frobber.frob();
    });
}

如果 ContinueWith 的目的是向链中添加另一个动作,为什么语言设计者不简单地传递上一个任务的结果?或者,在非泛型任务的情况下,需要一个无参数的操作?

【问题讨论】:

  • 如果任务抛出异常,前一个任务的结果是什么?
  • 考虑到非并行开发或 Promises,我希望有一个不同的方法签名来处理异常。 ContinueWith 向我暗示上一个任务已经完成,没有出错。
  • 顺便说一句,我认为使用ContinueWith(async t=&gt; { var result = await t ... }) 而不是.Result 是一种更好的做法,即使有人将操作复制粘贴到.Result 可能会阻止线程。

标签: .net task-parallel-library design-decisions


【解决方案1】:

ContinueWith 在任务进入task.IsCompleted == true 状态时运行委托。不是当它进入task.IsCompleted == true &amp;&amp; task.IsFaulted == false &amp;&amp; task.IsCanceled == false 状态时,抛出异常的任务或被取消的任务都“完成”但不会产生结果。

您可以在 TaskContinuationOptions 中传递一些重载,例如 TaskContinuationOptions.OnlyOnRanToCompletion 以获得您所描述的行为,但是对于单个枚举选项有一个 Action&lt;T&gt; 重载会更复杂,因此他们只使用一般Action&lt;Task&lt;T&gt;&gt; 的重载,因此如果您正在执行 OnlyOnRanToCompletion 或正在执行 OnlyOnFaulted,则可以使用相同的方法。

此外,在已完成任务的 Task 对象中仍有有用的信息,如果您使用 AsyncState 属性传递元数据,如果已完成的任务未传递给 ContinueWith,您将不会有除非您使用 lambda 表达式的变量捕获,否则获取该数据的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多