Seperti yang Anda temukan, di VS11 kompiler akan melarang async Main
metode. Ini diizinkan (tapi tidak pernah disarankan) di VS2010 dengan CTP Async.
Saya memiliki posting blog baru-baru ini tentang program konsol async / await dan asynchronous pada khususnya. Berikut beberapa informasi latar belakang dari pos pengantar:
Jika "menunggu" melihat bahwa yang ditunggu belum selesai, maka ia bertindak secara serempak. Ini memberitahu yang ditunggu untuk menjalankan sisa metode ketika selesai, dan kemudian kembali dari metode async. Menunggu juga akan menangkap konteks saat ini ketika melewati sisa metode ke menunggu.
Kemudian, ketika selesai menunggu, itu akan mengeksekusi sisa metode async (dalam konteks yang ditangkap).
Inilah mengapa ini menjadi masalah dalam program Konsol dengan async Main
:
Ingat dari pos intro kami bahwa metode async akan kembali ke pemanggilnya sebelum selesai. Ini berfungsi dengan baik di aplikasi UI (metode ini hanya kembali ke loop peristiwa UI) dan aplikasi ASP.NET (metode ini kembali dari utas tetapi menjaga permintaan tetap hidup). Itu tidak bekerja dengan baik untuk program-program Konsol: Main kembali ke OS - jadi program Anda keluar.
Salah satu solusinya adalah menyediakan konteks Anda sendiri - "loop utama" untuk program konsol Anda yang kompatibel dengan async.
Jika Anda memiliki mesin dengan CTP Async, Anda dapat menggunakan GeneralThreadAffineContext
dari My Documents \ Microsoft Visual Studio Async CTP \ Sampel (C # Testing) Unit Testing \ AsyncTestUtilities . Atau, Anda dapat menggunakan AsyncContext
dari paket NuGet Nito.AsyncEx saya .
Berikut ini contoh menggunakan AsyncContext
; GeneralThreadAffineContext
memiliki penggunaan yang hampir identik:
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();
}
}
Atau, Anda bisa memblokir utas Konsol utama sampai pekerjaan asinkron Anda selesai:
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();
}
}
Perhatikan penggunaan GetAwaiter().GetResult()
; ini menghindari AggregateException
pembungkus yang terjadi jika Anda menggunakan Wait()
atau Result
.
Pembaruan, 2017-11-30: Pada Visual Studio 2017 Pembaruan 3 (15,3), bahasa sekarang mendukung async Main
- selama kembali Task
atau Task<T>
. Jadi sekarang Anda dapat melakukan ini:
class Program
{
static async Task Main(string[] args)
{
Bootstrapper bs = new Bootstrapper();
var list = await bs.GetList();
}
}
Semantik tampaknya sama dengan GetAwaiter().GetResult()
gaya memblokir utas. Namun, belum ada spesifikasi bahasa untuk C # 7.1, jadi ini hanya asumsi.