Can someone please explain the difference between these two statements:
Task<Task> bTask = backup.BackupCurrentDatabaseAsync()
.ContinueWith(_ => CompressArchiveAsync());
//unwrap the tasks to produce one entire task
Task t = bTask.Unwrap();
vs
Task<Task> bTask = backup.BackupCurrentDatabaseAsync()
.ContinueWith(_ =>
{
CompressArchiveAsync();
});
//unwrap the tasks to produce one entire task
Task t = bTask.Unwrap();
The methodsExtractArchiveAsync()
, BackupCurrentDatabaseAsync()
, RestoreDatabaseAsync()
all return a Task
.
Here, the first Continuation returns a Task<Task>
. I can then Unwrap()
this task to put Continuations on the resultant (inner) task.
The second version doesn't compile. The only different here is the braces around the CompressArchiveAsync()
.
I am trying to access the resultant (internal) Task
to check the Task.Status
. If I use the second method, the Task.Status is reporting the result of the BackupCurrentDatabaseAsync()
task.
.ContinueWith(_ => CompressArchiveAsync());
is equivalent to:
.ContinueWith(_ =>
{
return CompressArchiveAsync();
});
Notice the return
.
Your second code snippet doesn't compile because ContinueWith
doesn't return a Task<Task>
, but simply a Task
, and there's nothing to unwrap.
The following is bound to a Func<Task, Task>
(a function that takes a Task
and returns a Task
)
_ =>
{
return CompressArchiveAsync();
}
But the following is actually bound to an Action<Task>
(a function that takes a Task
but doesn't return anything):
_ =>
{
CompressArchiveAsync();
}
And the reference to the Task
created by CompressArchiveAsync
is never returned. Without a reference to it, you can't check the Task
's status.
Note that:
ContinueWith<TResult>(Func<Task, TResult>)
returns a Task<TResult>
ContinueWith(Action<Task>)
returns a Task
.
Therefore your ContinueWith(Func<Task, Task>)
returns a Task<Task>
that you can unwrap, but your ContinueWith(Action<Task>)
simply returns a Task
.
The difference is in the Lambda Expression syntax.
There are 2 types of Lambdas: Expression Lambdas and Statement Lambdas. Expression Lambdas have no braces and return the result of the expression while Statement Lambdas have braces containing zero or more statements (one of them can be a return
statement).
So this Expression Lambda:
_ => CompressArchiveAsync()
Is equivalent to this Statement Lambda:
_ => { return CompressArchiveAsync(); }
So, the difference is that in the first continuation you are returning a task but in the second you are not, it's just a void anonymous delegate. That's why the first continuation is a Task<Task>
while the second is just a Task
.
Long comment to show 4.5 code.
If you could move to .Net 4.5 than code you are trying to write can be rewritten in more compact way with async/await which is essentially implements all that code internally:
async Task CompleteBackup()
{
await backup.BackupCurrentDatabaseAsync()
await CompressArchiveAsync());
await .....
}
In the first example, you are calling ContinueWith
with a Func
. Therefore, it will return a Task<T>
. The second try will call the ContinueWith
overload with an Action
, because... well it's an action, it does not return anything. So it will return a simple Task
without T
.