Crea un'attività completata


197

Voglio creare un completato Task(noTask<T> ). C'è qualcosa incorporato in .NET per fare questo?

Una domanda correlata: creare un'attività completata <T>


2
It seems like the answer I'm getting from everyone is that using a garbage value like this is the correct way. That there isn't a way to do this without the garbage value is disappointing -- oh well.Quali problemi pensi che questo abbia? Se ne memorizzi uno nella cache, Taskl'intero programma occupa un ulteriore bit di memoria. Non è niente . Inoltre, si potrebbe creare un'attività completata senza farlo, semplicemente non sarebbe meglio.
Servito il

10
Oh, la mia delusione non ha nulla a che fare con il dover usare memoria extra. È solo che i valori di immondizia in qualsiasi parte del codice non sono eleganti.
Timothy Shields,

1
Nota che oggi c'è ValueTaskper attività completate (cioè per valori che hai già in modo che il codice sia essenzialmente sincrono), il che ti farà risparmiare un'allocazione.
nawfal,

Risposte:


247

La versione più recente di .Net (v4.6) aggiunge proprio questo, un Task.CompletedTask integrato :

Task completedTask = Task.CompletedTask;

Quella proprietà è implementata come singleton senza blocco, quindi quasi sempre useresti la stessa attività completata.


1
Ho appena controllato l'ultimo CTP VS 14 e creato un progetto 4.5.3, Task.CompletedTaskè ancora interno.
Peter Ritchie,

1
2. O non hai scaricato l'ultimo CTP (che è 4 e collegato da quel sito) o non hai specificato la versione 4.5.3. Ecco cosa c'è sulla mia macchina . @PeterRitchie
i3arnon,

Ho creato una macchina virtuale dall'immagine di Visual Studio 14 su Azure.
Peter Ritchie,


Sto lavorando su Mac OS X con mono 5.4.1.7 e ottengo questo stesso errore. Come posso risolvere questo problema?
Khaled Annajar

153

Task<T>è implicitamente convertibile in Task, quindi basta ottenere un completato Task<T>(con Tqualsiasi valore) e utilizzarlo. Puoi usare qualcosa del genere per nascondere il fatto che un risultato reale è lì, da qualche parte.

private static Task completedTask = Task.FromResult(false);
public static Task CompletedTask()
{
    return completedTask;
}

Si noti che poiché non stiamo esponendo il risultato e l'attività è sempre completata, è possibile memorizzare nella cache un'unica attività e riutilizzarla.

Se stai usando .NET 4.0 e non lo FromResulthai, puoi crearne uno tuo usando TaskCompletionSource:

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}

8
Se stai usando 4.0, puoi aggiungere la libreria Microsoft.Bcl.Async per ottenere TaskEx.FromResult, così come altre cose utili come WhenAll
Carl

@Servy Cosa cambia da FromResult (false) e FromResult (true)?
Francesco Bonizzi,

3
@FrancescoB. Se stai guardando il risultato, cambia il valore booleano del risultato. Se stai ignorando il risultato, allora qual è il risultato è irrilevante.
Servito il

66

Il mio metodo preferito per farlo è chiamare Task.WhenAll()senza argomenti. La documentazione MSDN afferma che "Se l'array / l'enumerabile forniti non contiene attività, l'attività restituita passerà immediatamente allo stato RanToCompletion prima di essere restituita al chiamante". Sembra quello che vuoi.

Aggiornamento: ho trovato la fonte presso la fonte di riferimento di Microsoft ; lì puoi vedere che Task.WhenAll contiene quanto segue:

return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
            Task.CompletedTask :
            new WhenAllPromise(tasks);

Quindi Task.CompletedTask è effettivamente interno, ma viene esposto chiamando WhenAll () senza argomenti.


9
mentre sembra un po 'confuso, ha il supporto dei documenti, quindi non so, mi piace un po'!
Sara

2
Per me e il mio codice limitato .NET 4.5.2 è abbastanza elegante. Grazie!
Stas Ivanov,

36

Vorrei usare Task.Delay(0). Internamente, restituisce un'istanza memorizzata nella cache di un completato Task<T>. Questo è esattamente ciò che la risposta attuale suggerisce di fare comunque, solo ora non è necessario memorizzare nella cache un'istanza da soli, né nel codice sono presenti valori di immondizia non eleganti.

Potresti pensare che puoi usare Task.Yield()invece, ma si scopre che il risultato nonTask.Yield() è un sottotipo di , mentre il risultato di è. Questa è una delle sottili differenze tra i due.TaskTask.Delay(0)


30

È possibile utilizzare Task.FromResult (in .NET 4.5) per restituire un completato Task<T>.

Se hai bisogno di un non generico Task, puoi sempre usare Task.FromResult(0)o simili, poiché Task<T>è una sottoclasse di Task.


11

Per .Net 4.6 e versioni successive

return Task.CompletedTask;

Per la versione inferiore è possibile utilizzare

return new Task(() => { });

3
Per l'approccio pre 4.6, attenzione! È necessario avviare l'attività o non verrà mai completata! Che ne dici di usare return Task.Delay(0);invece?
Miquel,


0

Che ne dite di:

#pragma warning disable 1998
    public async Task emptyTask() {
    }
#pragma warning restore 1998

Puoi tralasciare la soppressione degli avvisi se non ti dispiace.


Ritengo che la marcatura di un metodo asynccrei ancora l'intero apparato della macchina a stati anche se non lo si utilizza, quindi la restituzione di un'attività vuota è più efficiente per scenari con risorse limitate.
Calvin Fisher,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.