Como você descobriu, no VS11, o compilador não permitirá um async Main
método. Isso foi permitido (mas nunca recomendado) no VS2010 com o CTP assíncrono.
Tenho postagens recentes no blog sobre os programas de console assíncrono / aguardado e assíncrono em particular. Aqui estão algumas informações básicas da publicação de introdução:
Se "aguardar" perceber que o aguardável não foi concluído, ele age de forma assíncrona. Ele diz ao aguardável para executar o restante do método quando ele é concluído e retorna do método assíncrono. Await também capturará o contexto atual quando passar o restante do método para o aguardável.
Posteriormente, quando o aguardável for concluído, ele executará o restante do método assíncrono (dentro do contexto capturado).
Veja por que esse problema ocorre nos programas de console com um async Main
:
Lembre-se do nosso post de introdução que um método assíncrono retornará ao chamador antes de ser concluído. Isso funciona perfeitamente em aplicativos de interface do usuário (o método apenas retorna ao loop de eventos da interface do usuário) e aplicativos ASP.NET (o método retorna do thread, mas mantém a solicitação ativa). Não funciona tão bem para os programas do console: Main retorna ao sistema operacional - para que seu programa saia.
Uma solução é fornecer seu próprio contexto - um "loop principal" para o seu programa de console compatível com async.
Se você tiver uma máquina com o CTP assíncrono, poderá usar GeneralThreadAffineContext
em Meus Documentos \ Microsoft Visual Studio CTP \ Amostras assíncronas \ Amostras (teste de C #) Testing \ AsyncTestUtilities . Alternativamente, você pode usar AsyncContext
a partir de meu pacote Nito.AsyncEx NuGet .
Aqui está um exemplo usando AsyncContext
; GeneralThreadAffineContext
tem uso quase idêntico:
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();
}
}
Como alternativa, você pode apenas bloquear o segmento principal do console até que seu trabalho assíncrono seja concluído:
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();
}
}
Observe o uso de GetAwaiter().GetResult()
; isso evita o AggregateException
acondicionamento que acontece se você usar Wait()
ou Result
.
Atualização, 30/11/2017: A partir da Atualização 3 do Visual Studio 2017 (15.3), o idioma agora suporta um async Main
- desde que retorne Task
ou Task<T>
. Agora você pode fazer isso:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
A semântica parece ser a mesma do GetAwaiter().GetResult()
estilo de bloqueio do encadeamento principal. No entanto, ainda não há especificação de idioma para o C # 7.1, portanto, isso é apenas uma suposição.