【问题标题】:How can I produce a Task<Task> to Unwrap如何生成要展开的 Task<Task>
【发布时间】:2015-02-16 06:12:12
【问题描述】:

谁能解释一下这两种说法的区别:

Task<Task> bTask = backup.BackupCurrentDatabaseAsync()
    .ContinueWith(_ => CompressArchiveAsync());
//unwrap the tasks to produce one entire task
Task t = bTask.Unwrap();

Task<Task> bTask = backup.BackupCurrentDatabaseAsync()
    .ContinueWith(_ => 
{
    CompressArchiveAsync();
});
//unwrap the tasks to produce one entire task
Task t = bTask.Unwrap();

ExtractArchiveAsync()BackupCurrentDatabaseAsync()RestoreDatabaseAsync() 方法都返回一个Task

在这里,第一个 Continuation 返回一个 Task&lt;Task&gt;。然后我可以Unwrap()这个任务将继续放在结果(内部)任务上。

第二个版本无法编译。这里唯一不同的是CompressArchiveAsync() 周围的大括号。

我正在尝试访问结果(内部)Task 以检查Task.Status。如果我使用第二种方法,Task.Status 将报告BackupCurrentDatabaseAsync() 任务的结果。

【问题讨论】:

  • 旁注:如果可能,考虑迁移到 4.5 和 async/awiat... 将产生更易于阅读的代码...
  • 不幸的是仍然在 4!在 4.5 中如何实现上述目标?
  • async/await 是 C# 5.0 的主要功能。虽然它仅在面向 .NET 4.5 时开箱即用,但您可以将异步目标包用于port it to .NET 4.0

标签: c# .net task-parallel-library async-await


【解决方案1】:

显示 4.5 代码的长注释。

如果您可以迁移到 .Net 4.5,那么您尝试编写的代码可以使用 async/await 以更紧凑的方式重写,这实际上是在内部实现所有代码:

 async Task CompleteBackup()
 {
    await backup.BackupCurrentDatabaseAsync()
    await CompressArchiveAsync());
    await .....
 }

【讨论】:

  • 感谢 Alexei,如果我有 TaskContinuationOptions 与我的 ContinueWith() 相关联,这种方法会更冗长吗?
  • @Simon 如果您需要对任务进行非常详细的控制,您可能仍需要直接使用ContinueWith 和类似的调用。我没有这样做,所以没有直接的建议。
  • @Simon:我推荐你使用这个基于await的代码。您可以通过安装 Microsoft.Bcl.Async package 将其与 .NET 4.0 桌面一起使用。使用await,已经提供了所有适当的TaskContinuationOptions,不需要那种级别的控制。
  • @Stephen Cleary - 谢谢,我会听取任务大师的建议
  • 吹毛求疵:async/await 是 C#5 功能(它针对 .NET 4.5+,但正如 Stephen Cleary 提到的,也可以在带有该包的 .NET 4.0 上使用)
【解决方案2】:

区别在于 Lambda 表达式语法。

有 2 种类型的 Lambda:表达式 Lambda语句 Lambda。表达式 Lambda 没有大括号并返回表达式的结果,而 Statement Lambda 有包含零个或多个语句的大括号(其中一个可以是 return 语句)。

所以这个表达式 Lambda:

_ => CompressArchiveAsync()

相当于这个语句 Lambda:

_ => { return CompressArchiveAsync(); }

因此,不同之处在于,在第一个延续中,您正在返回一个任务,但在第二个中您不是,它只是一个无效的匿名委托。这就是为什么第一个延续是 Task&lt;Task&gt; 而第二个只是 Task

【讨论】:

    【解决方案3】:
    .ContinueWith(_ => CompressArchiveAsync());
    

    相当于:

    .ContinueWith(_ => 
    {
        return CompressArchiveAsync();
    });
    

    注意return

    您的第二个代码 sn-p 无法编译,因为 ContinueWith 不返回 Task&lt;Task&gt;,而只是返回 Task,并且没有什么可解包的。

    以下内容绑定到 Func&lt;Task, Task&gt;(一个接受 Task 并返回 Task 的函数)

    _ => 
    {
        return CompressArchiveAsync();
    }
    

    但以下内容实际上绑定到 Action&lt;Task&gt;(一个接受 Task 但不返回任何内容的函数):

    _ => 
    {
        CompressArchiveAsync();
    }
    

    并且永远不会返回对CompressArchiveAsync 创建的Task 的引用。如果没有对其的引用,您将无法检查Task 的状态。

    注意:

    因此,您的 ContinueWith(Func&lt;Task, Task&gt;) 返回一个您可以解包的 Task&lt;Task&gt;,但您的 ContinueWith(Action&lt;Task&gt;) 只返回一个 Task

    【讨论】:

      【解决方案4】:

      在第一个示例中,您使用Func 调用ContinueWith。因此,它将返回一个Task&lt;T&gt;。第二次尝试将使用Action 调用ContinueWith 重载,因为...好吧,这是一个动作,它不会返回任何内容。所以它会返回一个简单的Task 而没有T

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-09
        • 2012-10-20
        • 1970-01-01
        • 2015-09-19
        • 2016-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多