简体   繁体   中英

How can I produce a Task<Task> to Unwrap

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 methods ExtractArchiveAsync() , 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:

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM