如何生成任务以解包
有人可以解释这两个陈述之间的区别:
Task bTask = backup.BackupCurrentDatabaseAsync() .ContinueWith(_ => CompressArchiveAsync()); //unwrap the tasks to produce one entire task Task t = bTask.Unwrap();
VS
Task bTask = backup.BackupCurrentDatabaseAsync() .ContinueWith(_ => { CompressArchiveAsync(); }); //unwrap the tasks to produce one entire task Task t = bTask.Unwrap();
ExtractArchiveAsync()
, BackupCurrentDatabaseAsync()
, RestoreDatabaseAsync()
都返回一个Task
。
这里,第一个Continuation返回一个Task
。 然后我可以Unwrap()
这个任务,将Continuations放在结果(内部)任务上。
第二个版本不编译。 这里唯一不同的是CompressArchiveAsync()
周围的大括号。
我试图访问结果(内部) Task
以检查Task.Status
。 如果我使用第二种方法,Task.Status将报告BackupCurrentDatabaseAsync()
任务的结果。
.ContinueWith(_ => CompressArchiveAsync());
相当于:
.ContinueWith(_ => { return CompressArchiveAsync(); });
注意return
。
你的第二个代码片段没有编译,因为ContinueWith
没有返回Task
,只是一个Task
,而且没有什么可以解包。
以下内容绑定到Func
(一个接受Task
并返回Task
的函数)
_ => { return CompressArchiveAsync(); }
但是以下实际上绑定到Action
(一个接受Task
但不返回任何内容的函数):
_ => { CompressArchiveAsync(); }
并且永远不会返回由CompressArchiveAsync
创建的Task
的引用。 如果没有引用它,则无法检查Task
的状态。
注意:
-
ContinueWith
返回一个(Func ) Task
-
ContinueWith(Action
返回一个) Task
。
因此,您的ContinueWith(Func
返回一个可以解包的Task
,但您的ContinueWith(Action
只返回一个Task
。
不同之处在于Lambda Expression语法。
Lambda有两种类型: Expression Lambdas和Statement Lambdas 。 表达式Lambda没有大括号并返回表达式的结果,而Statement Lambdas具有包含零个或多个语句的大括号(其中一个可以是return
语句)。
所以这个Expression Lambda:
_ => CompressArchiveAsync()
相当于本声明Lambda:
_ => { return CompressArchiveAsync(); }
所以,区别在于,在第一个延续中你返回一个任务,但在第二个你不是,它只是一个无效的匿名代表。 这就是为什么第一个延续是一个Task
而第二个继续是一个Task
。
长评显示4.5代码。
如果你可以移动到.Net 4.5,那么你试图编写的代码可以用async / await以更紧凑的方式重写,这实际上是在内部实现所有代码:
async Task CompleteBackup() { await backup.BackupCurrentDatabaseAsync() await CompressArchiveAsync()); await ..... }
在第一个示例中,您使用Func
调用ContinueWith
。 因此,它将返回Task
。 第二次尝试将使用Action
调用ContinueWith
重载,因为……好吧它是一个动作,它不会返回任何内容。 所以它将返回一个没有T
的简单Task
。