2015-01-13 13 views
7

Non sono sicuro se questo è possibile, ecco me out:passando un compito come parametro di

ho una sequenza di azioni da eseguire molteplici

async Task MethodA(...) 
{ 
    // some code 
    // a call to specific Async IO bound method 
    // some code 
} 

ci sono anche MethodB(), MethodC(), ecc e tutti hanno esattamente lo stesso codice, eccetto per la chiamata a un metodo associato ad Async I/O. Sto cercando di trovare un modo per passare un puntatore a un metodo, in modo che possiamo eseguirlo successivamente in un metodo().

Quello che sto facendo attualmente è questa:

private async Task Method(Func<Task<Entity>> func) 
{ 
    // some code 
    var a = await task.Run(func); 
    // some code 
} 

var task = async() => await CallToIOBoundTask(params); 
Method(task); 

Questo codice, però, tira un nuovo thread ogni volta, che non è richiesto per IO compito legato, e dovrebbero essere evitati.

Quindi, esiste un metodo per il refactoring del codice in modo che non venga utilizzato thread ThreadPool? Un obiettivo è avere un codice come questo:

private async Task Method(Task<Entity> task) 
{ 
    // some code 
    var a = await task; 
    // some code 
} 

È anche importante ricordare che diverse chiamate di I/O hanno differenti firme di metodo. Inoltre, un'attività può iniziare a essere eseguita solo nel corpo Method() e non prima.

+0

Si desidera attendere fino all'istruzione nel metodo 'Method()' per l'avvio dell'attività asincrona? In tal caso, l'esempio di codice nella domanda non è corretto (in attesa di un'attività _existing_ invece di crearne uno) e la risposta già fornita è ciò che desideri. Ma se vuoi solo essere in grado di attendere un'attività che hai iniziato prima che venga chiamato il metodo 'Method()', nota che puoi farlo facilmente: basta chiamare ad es. passare il valore di ritorno di una chiamata a 'CallToIOBoundTask()' come argomento per la chiamata al metodo 'Method()'. –

+0

@PeterDuniho Una risposta alla tua domanda è nell'ultima frase della domanda - L'attività deve iniziare la sua esecuzione in method(). – Goran

risposta

16

Naturalmente, è sufficiente richiamare il func, tornare un compito, e await è:

async Task Method(Func<Task<Entity>> func) 
{ 
    // some code 
    var a = await func(); 
    // some code 
} 

Inoltre, quando si sta inviando l'espressione lambda, dal momento che tutto ciò che sta facendo è chiamare un metodo che a async si restituisce un compito, non ha bisogno di essere async in sé:

Method(() => CallToIOBoundTask(params)); 

che va bene a patto che tutte queste chiamate ritornano Task<Entity>. In caso contrario, è possibile utilizzare solo Task (che significa avviare l'operazione e attendere il suo completamento) e non sarà possibile utilizzare il risultato.

+0

Heh, ho provato senza le parentesi e non ha funzionato. :) Come per il tuo secondo suggerimento, che cosa genererà IL per questa parte:() => CallToIOBoundTask (params)? Sarà un metodo di attività asincrona o no? Non riesco a generare questo codice come vuoto. – Goran

+0

@Goran Non sarà un metodo 'async'. Ma restituirà un compito poiché "CallToIOBoundTask" restituisce un'attività. Inoltre, non può essere nulla poiché il parametro non è un 'Action' ma 'Func >'. Se vuoi assicurarti di poter espandere quel lambda a '() => {return CallToIOBoundTask (params); } 'che è esattamente lo stesso. – i3arnon

Problemi correlati