Task concatenamento senza TaskCompletionSource?

Sto convertendo un codice asincrono / atteso in attività concatenate, quindi posso usarlo nel framework rilasciato. Il codice di attesa è come questo

public async Task Get() { var message = await Invoke("GET"); var memorized = await message.Memorize(); return memorized; } 

dove

 Task Invoke(string verb) {} Task Memorize() {} 

Speravo di mettere in catena Invoke e Memorize per restituire l’attività prodotta da Memorize , ma che risulta in un’attività Task<Task . La soluzione che ho trovato è TaskCompletionSource come mio segnale:

 public Task Get() { var completion = new TaskCompletionSource(); Invoke("GET").ContinueWith( t1 => { if(t1.IsFaulted) { completion.SetException(t1.Exception); return; } t1.Result.Memorize().ContinueWith( t2 => { if(t2.IsFaulted) { completion.SetException(t2.Exception); return; } completion.SetResult(t2.Result); }); }); return completion.Task; } 

C’è un modo per realizzare questo senza TaskCompletionSource ?

Penso che sia praticamente l’unico modo per realizzare ciò che vuoi. Concatenare i compiti disparati insieme non è supportato dalle API di continuazione, quindi è necessario ricorrere all’utilizzo di una TaskCompletionSource come se fosse necessario coordinare il lavoro.

Non ho installato Async CTP su questa macchina, ma perché non dai un’occhiata al codice con un decompilatore (o ILDASM se sai leggere IL) per vedere cosa sta facendo. Scommetto che fa qualcosa di molto simile al tuo codice TCS sotto le coperte.

Sì, il framework è dotato di un pratico metodo di estensione Unwrap () per esattamente quello che vuoi.

 Invoke("GET").ContinueWith( t => t.Result.Memorize() ).Unwrap(); 

Se stai facendo la cancellazione, dovrai passare i token di cancellazione nei posti appropriati, ovviamente.

È ansible utilizzare attività figlio allegate. L’attività principale passerà allo stato completato solo quando tutte le attività figlio saranno completate. Le eccezioni vengono propagate all’attività padre. È necessario un titolare del risultato, in quanto il risultato verrà assegnato dopo il completamento del delegato dell’attività principale, ma verrà impostato quando vengono eseguite le attività di continuazione dei genitori.

Come questo:

 public class Holder where T: class { public T Value { get; set; } } public Task> Get() { var invokeTask = Invoke("GET"); var result = invokeTask.ContinueWith>(t1 => { var holder = new Holder(); var memorizeTask = t1.Result.Memorize(); memorizeTask.ContinueWith(t2 => { holder.Value = t2.Result; }, TaskContinuationOptions.AttachedToParent); return holder; }); return result; }