Lancia un'eccezione all'interno di un'attività - "ATTENZIONE" vs wait ()
Domanda
static async void Main(string[] args)
{
Task t = new Task(() => { throw new Exception(); });
try
{
t.Start();
t.Wait();
}
catch (AggregateException e)
{
// When waiting on the task, an AggregateException is thrown.
}
try
{
t.Start();
await t;
}
catch (Exception e)
{
// When awating on the task, the exception itself is thrown.
// in this case a regular Exception.
}
}
In TPL, quando si lancia un'eccezione all'interno di un'attività, è avvolta da un Exception Aggregate.
Ma lo stesso non sta accadendo quando si usa il Aspetta parola chiave.
Qual è la spiegazione di quel comportamento?
Soluzione
L'obiettivo è farlo sembrare/agire come la versione sincrona. Jon Skeet fa un ottimo lavoro spiegando questo nella sua serie Eduasync, in particolare questo post:
http://codeblog.jonskeet.uk/2011/06/22/eduasync-part-11-more-sopicato-but-lossy-exception-handling/
Altri suggerimenti
In TPL AggregateException
viene utilizzato perché è possibile avere più attività nell'operazione di attesa (l'attività può avere attività per bambini allegate), quindi molte di esse possono lanciare eccezioni. Guarda a Eccezioni nei compiti di bambini Sezione qui:
https://msdn.microsoft.com/ru-ru/library/dd997417(v=vs.110).aspx
In await
Hai sempre solo un compito.
Guarda anche https://msdn.microsoft.com/ru-ru/library/dd997415(v=vs.110).aspx
Ecco una buona spiegazione nei dettagli, di Stephen Toub, perché c'è una differenza nel tipo di eccezione tra l'attività.Wait () e l'attesa:
Task Eccezioni gestite in .NET 4.5
Durante la progettazione di task.ait in .NET 4, abbiamo scelto di propagare sempre un aggregato. Tale decisione è stata influenzata dalla necessità di non sovrascrivere i dettagli, ma anche dal caso d'uso primario per le attività all'epoca, quella del parallelismo fork/join, in cui il potenziale per le eccezioni multiple è abbastanza comune.
Sebbene simile a Task.avere ad alto livello (cioè i progressi in avanti non vengono compiuti fino al completamento dell'attività), "Attesa dell'attività" rappresenta un insieme primario molto diverso di scenari. Invece di essere utilizzato per il parallelismo fork/join, l'uso più comune di "Abswit Task" è quello di prendere un pezzo di codice sequenziale e sincrono e trasformarlo in un pezzo di codice sequenziale e asincrono. In luoghi nel tuo codice in cui si esegue un'operazione sincrona, lo sostituisci con un'operazione asincrona rappresentata da un'attività e "si aspetta". Pertanto, mentre puoi certamente usare l'attesa per le operazioni di forcella/join (ad es. Utilizzo dell'attività. Inoltre, .NET 4.5 vede l'introduzione di System.Runtime.ExcectionServices.ExceptionDispatchInfo, che risolve il problema di consentire di fare il maresciallo attraverso i thread senza perdere dettagli di eccezione come Stack Trace e Watson Buckets. Dato un oggetto di eccezione, lo passiamo a ExceptionDispatchInfo.Create, che restituisce un oggetto ExceptionDisPatchInfo che contiene un riferimento all'oggetto di eccezione e una copia dei suoi dettagli. Quando è il momento di lanciare l'eccezione, l'eccezione che il metodo di lancio di DispatchInfo viene utilizzato per ripristinare il contenuto dell'eccezione e lanciarlo senza perdere le informazioni originali (le informazioni di Call Stack corrente vengono aggiunte a ciò che è già memorizzato nell'eccezione).
Detto questo, e di nuovo avere la scelta di lanciare sempre il primo o di lanciare sempre un aggregato, per "aspettare", optiamo di lanciare sempre il primo. Ciò non significa, tuttavia, di non avere accesso agli stessi dettagli. In tutti i casi, la proprietà dell'eccezione dell'attività restituisce ancora un Exception Aggregate che contiene tutte le eccezioni, in modo da poter catturare qualunque cosa venga lanciata e torna indietro per consultare Task.Exception quando necessario. Sì, questo porta a una discrepanza tra il comportamento delle eccezioni quando si passa tra "Task.Wait ()" e "Attesa attività", ma l'abbiamo visto come il significativo minore di due mali.