Come hai scoperto, in VS11 il compilatore non consentirà un async Main
metodo. Ciò è stato consentito (ma mai consigliato) in VS2010 con Async CTP.
Ho post recenti sul blog in particolare su programmi asincroni / waitit e console asincrone . Ecco alcune informazioni di base dal post introduttivo:
Se "wait" vede che l'atteso non è stato completato, agisce in modo asincrono. Indica l'attesa di eseguire il resto del metodo al termine, quindi ritorna dal metodo asincrono. Attendere inoltre catturerà il contesto attuale quando passa il resto del metodo all'atteso.
Più tardi, quando l'atteso sarà completato, eseguirà il resto del metodo asincrono (nel contesto acquisito).
Ecco perché questo è un problema nei programmi della console con un async Main
:
Ricorda dal nostro post introduttivo che un metodo asincrono tornerà al suo chiamante prima che sia completo. Funziona perfettamente nelle applicazioni dell'interfaccia utente (il metodo ritorna solo al ciclo degli eventi dell'interfaccia utente) e nelle applicazioni ASP.NET (il metodo restituisce il thread ma mantiene attiva la richiesta). Non funziona così bene per i programmi della console: Main ritorna al sistema operativo, quindi il programma viene chiuso.
Una soluzione consiste nel fornire il proprio contesto: un "ciclo principale" per il programma della console compatibile asincrono.
Se si dispone di un computer con CTP asincrono, è possibile utilizzare GeneralThreadAffineContext
da Documenti \ CTP asincrono Microsoft Visual Studio \ Samples (test C #) Test unit \ AsyncTestUtilities . In alternativa, è possibile utilizzare AsyncContext
dal mio pacchetto NuGet Nito.AsyncEx .
Ecco un esempio usando AsyncContext
; GeneralThreadAffineContext
ha un utilizzo quasi identico:
using Nito.AsyncEx;
class Program
{
static void Main(string[] args)
{
AsyncContext.Run(() => MainAsync(args));
}
static async void MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
In alternativa, puoi semplicemente bloccare il thread della console principale fino al completamento del lavoro asincrono:
class Program
{
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Si noti l'uso di GetAwaiter().GetResult()
; questo evita l' AggregateException
avvolgimento che si verifica se si utilizza Wait()
o Result
.
Aggiornamento, 30-11-2017: a partire da Visual Studio 2017 Aggiornamento 3 (15.3), la lingua ora supporta un async Main
- fintanto che ritorna Task
o Task<T>
. Quindi ora puoi farlo:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
La semantica sembra essere la stessa dello GetAwaiter().GetResult()
stile di blocco del thread principale. Tuttavia, non ci sono ancora specifiche linguistiche per C # 7.1, quindi questo è solo un presupposto.