Gestione asincrona delle eccezioni con vuoto

Sto usando Async CTP per scrivere un’app di console pesante IO. Ma sto avendo problemi con le eccezioni.

public static void Main() { while (true) { try{ myobj.DoSomething(null); } catch(Exception){} Console.Write("done"); //... } } //... public async void DoSomething(string p) { if (p==null) throw new InvalidOperationException(); else await SomeAsyncMethod(); } 

E succede il seguente: “done” viene scritto nella console, poi ottengo l’eccezione nel debugger, poi premo per continuare il mio programma esiste .
Cosa dà?

Quando si chiama DoSomething() , in pratica, viene creata un’attività sotto il cofano e viene avviata l’ Task . Dato che hai una firma void , non c’è nessun object Task da segnalare o che avresti potuto bloccare, quindi l’esecuzione è passata direttamente al completamento. Nel frattempo il compito genera un’eccezione, che nessuno sta prendendo, che, sospetto, è il motivo per cui il tuo programma termina.

Penso che il comportamento che volevi fosse più simile a questo:

 public static void Main() { while (true) { var t = myobj.DoSomething(null); t.Wait(); if(t.HasException) { break; } } Console.Write("done"); //... } } //... public async Task DoSomething(string p) { if (p==null) throw new InvalidOperationException(); else await SomeAsyncMethod(); } 

Ciò bloccherà su ogni DoSomething fino a quando non sarà DoSomething uscirà dal ciclo se DoSomething gettato. Certo, allora non stai facendo nulla di async. Ma dallo pseudo codice, non riesco a capire cosa volessi accadere in modo asincrono.

Main take-away: l’uso di void per un metodo asincrono significa perdere la possibilità di ottenere l’eccezione a meno che non si sia in await quel metodo asincrono. Come una chiamata di sincronizzazione, in pratica pianifica solo il lavoro e il risultato scompare nell’etere.

Se si fornisce all’applicazione Console un contesto compatibile asincrono (ad es. AsyncContext ( docs , source ) dalla libreria AsyncEx), è ansible rilevare eccezioni che si propagano al di fuori di tale contesto, anche da metodi di async void :

 public static void Main() { try { AsyncContext.Run(() => myobj.DoSomething(null)); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); } Console.Write("done"); } public async void DoSomething(string p) { if (p==null) throw new InvalidOperationException(); else await SomeAsyncMethod(); }