2015-03-04 2 views
8

Ho una classe di base che fornisce un metodo con la seguente firma:Cosa dovrei usare come manichino attendibile?

virtual async Task RunAsync() 

classi derivate dovrebbero sostituire questa implementazione con qualcosa di simile

public override async Task RunAsync() 
{ 
    await base.RunAsync(); 
    await this.DoSomethingElse(); 
} 

Ora il compilatore mi dà un avvertimento che la Base. RunAsync è privo di un'attesa. Voglio che il mio codice sia privo di avvertimenti, non sopprima gli avvisi e che funzioni senza dover fornire controlli nulli anche se la classe derivata non fornisce un'implementazione di override, quindi non è possibile utilizzare virtual Task RunAsync() (omettendo la parola chiave async).

Per ora l'implementazione nel metodo base è await Task.Delay(0); che disattiva l'avviso del compilatore, ma in qualche modo non è "pulito" secondo me. Qual è il modo giusto per affrontare questo argomento?

+0

Task.FromResult è probabilmente quello che stai cercando – Zache

+1

O questo: https://msdn.microsoft.com/it us/library/system.threading.tasks.task.completedtask (v = vs.110) .aspx – Zache

+0

Questa sembra un'implementazione divertente. Perché non utilizzare 'RunAsync' come metodo non virtuale e creare un metodo' Abstract' 'RunAsyncInternal' che' RunAsync' chiamerà con 'await' - questo cancellerà anche il tuo avviso. – rhughes

risposta

9

Non si capisce come funziona async. Non fa parte della firma, quindi se non lo hai il await, in realtà non devi usarlo. Quindi, anche se si sta fornendo un metodo Task RunAsync(), si può semplicemente scrivere senza la async, ad esempio:

virtual Task RunAsync() 
{ 
    return Task.FromResult(false); 
} 

Questo consente comunque di effettuare un override che in effetti utilizzare await, in questo modo:

override async Task RunAsync() 
{ 
    await base.RunAsync(); 
    await DoSomeOtherStuffAsync(); 
} 

Questo è il motivo per cui il compilatore ti dà l'avvertimento - la parola chiave asyncè completamente inutile, e non fa parte della firma del metodo. E 'solo un segnale al compilatore che è permesso usare l'identificatore await come parola chiave, fondamentalmente - per mantenere la retrocompatibilità con il vecchio codice C#.

EDIT:

Come notato da Jeroen Mostert nei commenti, dal .NET Framework 4.6, la proprietà Task.CompletedTask è pubblico, in modo da poter fare questo:

virtual Task RunAsync() 
{ 
    return Task.CompletedTask; 
} 

Quindi, se si può usare 4.6+, questa è l'opzione più nuova e più pulita. E, naturalmente, se è necessario restituire effettivamente un valore, Task.FromResult è ancora lì :)

+0

'Task.FromResult' è stato nuovo per me. Ancora - e ovviamente non è colpa tua - Task.FromResult (false) sembra ancora una soluzione alternativa a causa del const falso usato per chiamare il metodo (paragonabile a Task.Delay (0) IMHO).Tuttavia il framework non offre qualcosa come 'Task.FromResult' per fornire un task non T al suo stato completato. Mi piacerebbe sapere l'opinione/ragionamento di @ Eric-Lippert su questo ... – David

+3

@David: Il framework * non * offre che - è [Task.CompletedTask] (https://msdn.microsoft.com/library/ VStudio/system.threading.tasks.task.completedtask). –

+2

Naturalmente, ora vedo che è molto, molto recente - dal 4.6 in poi. Comunque, meglio tardi che mai. :-) –