2014-12-17 18 views
8

Qualcuno può spiegare la differenza tra queste due affermazioni:Come posso produrre un task <Task> a scartare

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(); 

I metodi ExtractArchiveAsync(), BackupCurrentDatabaseAsync(), RestoreDatabaseAsync() tutto restituiscono un Task.

Qui, il primo Continuazione restituisce un Task<Task>. Posso quindi eseguire l'attività Unwrap() per continuare con l'attività risultante (interna).

La seconda versione non viene compilata. L'unica differenza qui sono le parentesi graffe attorno allo CompressArchiveAsync().

Sto tentando di accedere al risultante (interno) Task per controllare lo Task.Status. Se utilizzo il secondo metodo, Task.Status sta segnalando il risultato dell'attività BackupCurrentDatabaseAsync().

+0

Nota a margine: prevedere il passaggio a 4.5 e async/awiat se possibile ... Produrrà codice più facile da leggere ... –

+0

Purtroppo ancora sul 4! Come si raggiungerebbe quanto sopra in 4.5? – Simon

+0

'async' /' await' è una funzionalità C# 5.0. Anche se funziona come previsto per .NET 4.5, puoi utilizzare il pacchetto di targeting asincrono per [portarlo su .NET 4.0] (http://stackoverflow.com/questions/9110472/using-async-await-on net-4). – CodesInChaos

risposta

11
.ContinueWith(_ => CompressArchiveAsync()); 

è equivalente a:

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

Avviso del return.

Il codice secondo frammento di non viene compilato perché ContinueWith non restituisce un Task<Task>, ma semplicemente un Task, e non c'è niente da scartare.

Di seguito è legata ad una Func<Task, Task> (una funzione che prende un Task e restituisce un Task)

_ => 
{ 
    return CompressArchiveAsync(); 
} 

Ma il seguente è in realtà associato a un Action<Task> (una funzione che prende un Task, ma non lo fa restituire nulla):

_ => 
{ 
    CompressArchiveAsync(); 
} 

E il riferimento al Task creato da CompressArchiveAsync non è mai tornato. Senza un riferimento ad esso, non è possibile controllare lo stato di Task.

Nota che:

quindi il vostro ContinueWith(Func<Task, Task>) restituisce un Task<Task> che si può scartare, ma il vostro ContinueWith(Action<Task>) restituisce semplicemente un Task.

3

La differenza è nella sintassi Lambda Expression.

Ci sono 2 tipi di Lambda: Espressione lambda e Dichiarazione lambda. Expression Lambdas non ha parentesi e restituisce il risultato dell'espressione mentre Statement Lambdas ha parentesi contenenti zero o più istruzioni (una di esse può essere una dichiarazione return).

Quindi questa espressione lambda:

_ => CompressArchiveAsync() 

è equivalente a questa Normativa Lambda:

_ => { return CompressArchiveAsync(); } 

Quindi, la differenza è che nel primo prosecuzione si restituisce un compito, ma nel secondo si no, è solo un vuoto delegato anonimo. Ecco perché la prima continuazione è una Task<Task> mentre la seconda è solo una Task.

1

Nel primo esempio, si chiama ContinueWith con un Func. Pertanto, restituirà un Task<T>. Il secondo tentativo chiamerà il sovraccarico ContinueWith con un Action, perché ... beh è un'azione, non restituisce nulla. Quindi restituirà un semplice Task senza T.

2

Commento lungo per mostrare il codice 4.5.

Se si potesse passare a .Net 4.5 di codice che si sta tentando di scrivere può essere riscritta in modo più compatto con async/await che è essenzialmente implementa tutto ciò che il codice interno:

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

Grazie Alexei, se ho 'TaskContinuationOptions' associato al mio' ContinueWith() '', questo metodo sarebbe più dettagliato? – Simon

+0

@Simon Se è necessario un controllo molto dettagliato sulle attività, è probabile che sia necessario utilizzare ancora 'ContinueWith' e chiamate simili direttamente. Non l'ho fatto quindi nessun consiglio diretto. –

+0

@Simon: ti consiglio di usare questo codice basato su "attendi". È possibile utilizzarlo con .NET 4.0 Desktop installando il [pacchetto Microsoft.Bcl.Async] (https://www.nuget.org/packages/Microsoft.Bcl.Async/). Con 'await', tutte le appropriate' TaskContinuationOptions' sono già fornite, e non c'è bisogno di quel livello di controllo. –

Problemi correlati