Chiamare un metodo asincrono da un metodo non asincrono

Ogni variante del seguente codice che provo non funziona, sia DoSomething() : void e viene chiamato come scritto, o DoSomething() : Task e viene chiamato con TaskEx.RunEx() , un tentativo che coinvolge .GetAwaiter().GetResult() . Gli errori visualizzati includono: "Start may not be called on a task with null action" , "RunSynchronously may not be called on a task unbound to a delegate" e "The task has not yet completed" .

 class Program { static void Main(string[] args) // Starting from a non-async method { DoSomething(); Console.WriteLine("Press any key to quit."); Console.ReadKey(); } static async void DoSomething() { Console.WriteLine("Starting DoSomething ..."); var x = await PrepareAwaitable(1); Console.WriteLine("::" + x); var y = await PrepareAwaitable(2); Console.WriteLine("::" + y); } static Task PrepareAwaitable(int id) { return new Task(() => { return "Howdy " + id.ToString(); }); } } 

Produzione:

Avvio di DoSomething …

Premere qualsiasi tasto per uscire.

PrepareAwaitable l’azione del Task PrepareAwaitable sarà più complicato in seguito. Quando questa azione termina, per quanto sia lungo, mi aspetto che il Task (o altri meccanismi del Framework) riprenda assegnando "Howdy ..." a x, e successivamente a y. Quello che voglio REALMENTE fare è intercettare gli oggetti attesi, elaborarli, e in un secondo momento che controllo, riprendere la continuazione con un risultato ( y ). Ma non sono stato molto lontano da quel grande passo, quindi sto cercando di iniziare più piccolo.

Le attività che hai restituito non sono ancora state avviate (cioè sono attività “fredde”); prova a sostituire il codice PrepareAwaitable con quanto segue:

 static Task PrepareAwaitable(int x) { return Task.Factory.StartNew(() => { return "Howdy " + x.ToString(); }); } 

Innanzitutto, leggere il documento Pattern asincrono basato su attività. È in My Documents\Microsoft Visual Studio Async CTP\Documentation . Questo documento descrive come progettare le API naturalmente consumabili in await .

In secondo luogo, rendersi conto che esistono diversi aspetti della class Task e delle API correlate che non si applicano più realmente al nuovo mondo asincrono. Task stata originariamente scritta come il nucleo di TPL. Si è rivelato adatto per la programmazione asincrona, quindi Microsoft lo ha usato invece di creare una nuova class “Promise”. Ma un certo numero di metodi sono gli holdover, usati da TPL ma non necessari per la programmazione asincrona.

Per rispondere alla domanda principale, la combinazione di codice sincrono e asincrono non è abbastanza semplice con il CTP asincrono corrente. Ho scritto una libreria che include un metodo di estensione Task.WaitAndUnwrapException , che rende facile chiamare il codice asincrono dal codice di sincronizzazione. Potresti anche essere interessato alla mia class AsyncContext , che rende superfluo il prompt “premere un tasto qualsiasi”.

Non è davvero chiaro cosa stai cercando di ottenere, perché non c’è nulla di asincrono in corso. Ad esempio, questo verrà compilato ed eseguito, ma non so se è quello che vuoi:

 using System; using System.Threading.Tasks; class Program { static void Main(string[] args) { DoSomething(); Console.WriteLine("Press any key to quit."); Console.ReadKey(); } static async void DoSomething() { Console.WriteLine("Starting DoSomething ..."); var x = await PrepareAwaitable(1); Console.WriteLine("::" + x); var y = await PrepareAwaitable(2); Console.WriteLine("::" + y); } static async Task PrepareAwaitable(int x) { return "Howdy " + x; } } 

Si noti che questo fornisce un avviso per PrepareAwaitable perché non c’è nulla di asincrono in esso; nessuna espressione “attendi”. L’intero programma viene eseguito in modo sincrono. Un’altra implementazione alternativa di PrepareAwaitable :

 static Task PrepareAwaitable(int x) { return TaskEx.Run(() => "Howdy " + x); } 

È più come quello che cercavi?