6

Ho un metodo Async che restituisce un'attività.Schema per l'implementazione dei metodi di sincronizzazione in termini di attività non parallela (traslazione/annullamento delle eccezioni Aggregate)

Desidero anche offrire un equivalente sincrono, ma non voglio che i consumatori debbano andare a decomprimere AggregateException s.

Ora ho capito che l'idea è che non si poteva scegliere uno arbitrariamente in modo generale, e so che potrei andare a leggere i carichi più articoli Stephen Toub (io voglio, ma non ora) e capirò tutto e può decidere per me stesso.

Nel frattempo, desidero utilizzare il fatto che i miei compiti sono in realtà solo "flussi di lavoro" concatenati senza parallelismo, solo intervenienti Waits (no, non TPL DataFlow) che non dovrebbero comportare più di un'eccezione. In tal caso, sarebbe opportuno per gestire nel modo seguente:

CallAsync().Wait(); 
} 
catch(AggregateException ae) 
{ 
    throw ae.Flatten().First() 

o sono io garantito che un AggregateException ha sempre un InnerException anche se ci sono più di uno. O c'è un caso in cui dovrei tornare a .Flatten().First()?


In alcuni documenti TPL, vedo un riferimento ad un metodo di Unwrap() su AggregateException (non so se fosse un'estensione o qualcosa in una versione beta).

come segnaposto, che sto facendo:

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     var translated = ex.InnerException ?? ex.Flatten().InnerExceptions.First(); 
     if (translated == null) 
      throw; 
     throw translated;     } 
} 

Task CallAsync(){ ... 

risposta

21

Non c'è alcun modo "pulito" per fare questo, che io sappia. Non è possibile utilizzare throw someInnerException; perché si perderà lo stack dovunque l'eccezione abbia avuto origine nel flusso di lavoro asincrono e se si utilizza semplicemente throw;, ovviamente si propagherà lo AggregateException. Quello che dovresti fare per il metodo sincrono è avere qualche tipo di eccezione "wrapper" che puoi riempire la prima eccezione dello AggregateException e poi lanciarlo coerentemente dalla versione sincrona del metodo.

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     throw new MyConsistentWrapperException("An exception occurred while executing my workflow. Check the inner exception for more details.", ex.Flatten().InnerExceptions.First()); 
    } 
} 

FWIW, hanno risolto questo in 4.5 con the new ExceptionDispatchInfo class che vi aiuterà a marshalling eccezioni attraverso le discussioni, senza whacking lo stack. Quindi è possibile scrivere la versione sincrona in questo modo:

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     ExceptionDispatchInfo.Capture(ex.Flatten().InnerExceptions.First()).Throw(); 
    } 
} 
+1

Grazie; specialmente per il punto di perdita della pila che avevo preso in considerazione e poi ho chiuso un occhio (non so nemmeno se il normale trucco PreserveStackTrace funzionerebbe come se fossi in media fiducia, quindi non posso nemmeno provarlo). Domanda finale però (e il mio vero punto di partenza) - qualsiasi idea sul perché la maggior parte dei campioni usa '.InnerException' invece di' .Flatten(). InnerExceptions.First() 'o qualche altro modo di scartare - ** sono equivalenti o meno **? Se sì, qualche riferimento? Ci sono altri modi per scartare - qualsiasi link apprezzato ... –

+0

Se dai un'occhiata ai costruttori di AggregateException con ILDasm vedrai che alla fine c'è un costruttore privato di (string, IList ) a cui le altre implementazioni delegano e in quel costruttore chiamano il costruttore di base Exception che passa la prima eccezione nel IList come parametro innerException. Tuttavia, poiché la prima eccezione potrebbe essere tecnicamente un'altra AggregateException, l'utilizzo di Flatten() è il modo garantito per ottenere la prima eccezione di base non AggregateException. –

+0

Fantastico, lo ha spiegato perfettamente. Vorrei che una delle 50 pagine di documenti e articoli potesse spiegarlo come succintamente. (Devo ancora avere a TPL w/un decompilatore - per qualche ragione lo considero mentalmente off limits.Per quanto riguarda il modo in cui spiego di non assumere questo atteggiamento in WCF ...: D) –

Problemi correlati