2013-05-14 17 views
7

sto cercando di eseguire il codice seguente:Perché questa eccezione non viene rilevata?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var task = Task.Factory.StartNew(() => 
      { 
       throw new ApplicationException("message"); 
      }); 
     try 
     { 
      task.ContinueWith(t => Console.WriteLine("End")); 
     } 
     catch (AggregateException aex) 
     { 
      Console.Write(aex.InnerException.Message); 
     } 
    } 
} 

mi aspettavo che il Exception sarebbe stato catturato nella seguente posizione:

 catch (AggregateException aex) 
     { 
      Console.Write(aex.InnerException.Message); 
     } 

Ma questo non sta accadendo. Perché è così?

+0

Le risposte hanno indicato cosa e come fare ma non il "perché" (l'eccezione non viene rilevata). Credo che questo razionale sia importante da comprendere ed è spiegato nell'articolo di Stephen Toub [Task Exception Handling in .NET 4.5] (http://blogs.msdn.com/b/pfxteam/archive/2011/09/28/10217876. aspx) che è una lettura obbligata] –

risposta

9

Stai solo stampando la task - quali no anche completato ancora.

La stampa dell'attività non attende il completamento o tenta di recuperare il valore.

Se si modifica il codice per:

try 
{ 
    task.Wait(); 
} 

... poi mi aspetto che per catturare l'eccezione.

(ero in precedenza utilizzando Task<T>.Result, ma ho notato che questo è un compito senza alcun valore di ritorno, quindi sarebbe solo il non generico Task.)

+0

@NominSim No. Lo stesso delegato non è stato ancora eseguito quando restituisce "StartNew".Non può generare un'eccezione su quella linea quando l'eccezione non è stata ancora raggiunta. – Servy

+1

@NominSim: viene catturato dal blocco della proprietà 'Result'. –

+1

@NominSim Il 'ApplicationException' viene lanciato dall'altro thread. In quel thread, che sta chiamando il delegato anonimo fornito, alla fine verrà catturato (in un blocco catch da qualche parte all'interno del codice 'Task'). Non viene ri-generato dal thread principale quando viene creata l'attività. Quando il thread principale quindi attende l'attività, una volta completata l'attività, noterà che l'attività è terminata con un'eccezione di primo livello; tale eccezione viene quindi ri-generata (in un 'AggregateException') nel thread principale perché questo è ciò che l'implementazione del metodo 'Wait' fa esplicitamente. – Servy

-4

Causa la sua dichiarazione non è nella prova, ma prima ... catch sarà catturare ogni eccezione all'interno della provare parentesi graffe ...

+3

Penso che tu abbia frainteso la natura dei compiti. –

+0

Questo semplicemente non è vero. Un facile contro-esempio: imposta il corpo del blocco 'try' come' task.Result' e finirà per rigettare l'eccezione generata nel delegato che definisce l'attività. – Servy

+0

@Jon Skeet> Vedendo i downvotes, penso di aver frainteso l'intera domanda :-) –

1

Il modo Task opere, il codice che finisce per chiamare il delegato passato a StartNew verrà catturato, eventualmente, e lo Exception verrà archiviato in un campo di istanza dell'attività. Questa eccezione può essere ispezionata guardando la proprietà task.Exception. La linea Console.WriteLine(task) chiama semplicemente task.ToString internamente. Questo metodo non si tradurrà nell'eccezione di essere lanciati o rigiocati.

Tuttavia, in determinate circostanze l'eccezione che viene catturata verrà nuovamente generata. Due esempi sono quando si accede a Result e chiamando , nonché quando si esegue l'operazione await in C# 5.0.

Il seguente codice:

try 
{ 
    task.Wait(); 
} 
catch (AggregateException aex) 
{ 
    Console.Write(aex.InnerException.Message); 
} 

comporterà l'esclusione memorizzati in fase di ri-gettato e il messaggio di eccezione verrà stampato.

+0

Tranne che, anche con un punto e virgola, non è possibile utilizzare un accesso come un'istruzione autonoma. –

+0

@LuisFilipe Ho già modificato l'errore a cui si riferisce. Basta vedere la cronologia delle revisioni. – Servy

+0

@LuisFilipe In realtà, l'ho risolto nella finestra dei 5 minuti, quindi non sarà nemmeno nella cronologia delle revisioni; ma ho avuto un errore che da allora ho risolto. – Servy

-2

AggregateException e ApplicationException sono entrambi figli della stessa classe, System.Exception. AggregateException non è un ApplicationException

+1

Questo è irrilevante. Nessuna eccezione di nessun tipo è mai stata lanciata dal blocco 'try' dell'OP. – Servy

+0

Sì, ho intenzione di uscire su un arto e dire che 'lancio nuova ApplicationException (" messaggio ");' non è stata la vera implementazione di questa attività. Potrebbe essere stato un errore di battitura nel creare l'esempio e non avere nulla a che fare con il vero problema. –

+0

@NickFreeman Nope. Non è affatto vero. La classe 'Task' comprenderà qualsiasi eccezione generata dal suo corpo in una' AggregateException', quindi l'uso di tale eccezione è appropriato. Il problema, come descrivo nella mia risposta, è che l'OP deve usare 'task.Wait()'. Questo piccolo cambiamento porta il programma a funzionare esattamente come previsto. – Servy

Problemi correlati