Como descubrió, en VS11 el compilador no permitirá un async Main
método. Esto fue permitido (pero nunca recomendado) en VS2010 con el Async CTP.
Tengo publicaciones de blog recientes sobre programas de consola asíncronos / en espera y asíncronos en particular. Aquí hay información de fondo de la publicación de introducción:
Si "esperar" ve que lo esperable no se ha completado, entonces actúa de forma asíncrona. Le dice a la persona que espera ejecutar el resto del método cuando se complete, y luego regresa del método asíncrono. Await también capturará el contexto actual cuando pase el resto del método a lo esperado.
Más adelante, cuando se complete lo esperado, ejecutará el resto del método asíncrono (dentro del contexto capturado).
He aquí por qué este es un problema en los programas de consola con un async Main
:
Recuerde de nuestra publicación de introducción que un método asincrónico volverá a la persona que llama antes de que se complete. Esto funciona perfectamente en aplicaciones de UI (el método solo regresa al bucle de eventos de UI) y en aplicaciones ASP.NET (el método regresa del hilo pero mantiene viva la solicitud). No funciona tan bien para los programas de consola: Main regresa al sistema operativo, por lo que su programa se cierra.
Una solución es proporcionar su propio contexto: un "bucle principal" para su programa de consola que sea compatible con la sincronización.
Si tiene una máquina con el CTP asíncrono, puede usar GeneralThreadAffineContext
desde Mis documentos \ Microsoft Visual Studio CTP asíncrono \ Muestras (Prueba de C #) Prueba de unidad \ AsyncTestUtilities . Alternativamente, puede usar AsyncContext
desde mi paquete Nito.AsyncEx NuGet .
Aquí hay un ejemplo usando AsyncContext
; GeneralThreadAffineContext
tiene un uso casi 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();
}
}
Alternativamente, puede bloquear el hilo principal de la consola hasta que su trabajo asincrónico se haya completado:
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();
}
}
Tenga en cuenta el uso de GetAwaiter().GetResult()
; esto evita la AggregateException
envoltura que ocurre si usa Wait()
o Result
.
Actualización, 2017-11-30: a partir de Visual Studio 2017 Actualización 3 (15.3), el idioma ahora admite un async Main
- siempre que regrese Task
o Task<T>
. Entonces ahora puedes hacer esto:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
La semántica parece ser la misma que el GetAwaiter().GetResult()
estilo de bloquear el hilo principal. Sin embargo, todavía no hay especificaciones de lenguaje para C # 7.1, por lo que esto es solo una suposición.