2014-09-18 13 views
12

Heute haben meine Kollegen und ich besprochen, wie Exceptions in C# 5.0 async Methoden korrekt behandelt werden, und wir haben uns gefragt, ob das Warten auf mehrere Tasks gleichzeitig auch die Exceptions berücksichtigt, die von der Runtime nicht ausgepackt werden.Werden mehrere Aufgaben warten mehr als die erste Ausnahme beachten?

Betrachten Sie den folgenden Code-Schnipsel:

async Task ExceptionMethodAsync() 
{ 
    await Task.Yield(); 
    throw new Exception(); 
} 

async Task CallingMethod() 
{ 
    try 
    { 
     var a = ExceptionMethodAsync(); 
     var b = ExceptionMethodAsync(); 

     await Task.WhenAll(a, b); 
    } 
    catch(Exception ex) 
    { 
     // Catches the "first" exception thrown (whatever "first" means) 

    } 
} 

Was jetzt auf die zweite Aufgabe geschieht? Beide werden in einem fehlerhaften Zustand sein, aber ist die zweite Aufgabe nun eine Ausnahme oder unbeobachtet?

+0

Beide werden beobachtet. –

+0

Das Buch C# in der Tiefe diskutiert dieses Problem, Sie können die Antwort dort finden. – Matt

Antwort

26

Task.WhenAll gibt eine Aufgabe zurück und wie alle Aufgaben enthält die Exception-Eigenschaft eine AggregateException, die alle Ausnahmen kombiniert.

Wenn Sie eine solche Aufgabe await nur die erste Ausnahme wird tatsächlich ausgelöst werden.

... Ob wegen der Kinder Aufgaben, die Störung oder wegen combinators wie Task.WhenAlll, eine einzelne Aufgabe mehrere Operationen darstellen können, und mehr als einer von denen, bemängeln kann. In einem solchen Fall und mit dem Ziel, keine Ausnahmeinformationen zu verlieren (was für das Post-Mortem-Debugging wichtig sein kann), möchten wir in der Lage sein, mehrere Ausnahmen darzustellen, und daher wählten wir für den Wrappertyp AggregateException.

... Da, wieder mit der Wahl von immer den ersten Wurf oder immer ein Aggregat zu werfen, für „erwarten“ wir die ersten

von Task Exception Handling in .NET 4.5

Es ist immer zu werfen entscheiden an Sie zu wählen, wenn Sie nur die erste mit await task; (in den meisten Fällen wahr) behandeln oder alle mit task.Exception (wie in meinem Beispiel unten) behandeln, aber in beiden Fällen a und b würde keine UnobservedTaskException auslösen.

var task = Task.WhenAll(a, b); 
try 
{ 
    await task; 
} 
catch 
{ 
    Trace.WriteLine(string.Join(", ", task.Exception.Flatten().InnerExceptions.Select(e => e.Message))); 
} 
+0

Sollen wir 'task.Exception.Handle (_ => true)' auf dem Catch aufrufen oder werden die untergeordneten Ausnahmen als "behandelt" markiert, indem 'await' verwendet wird? – jorgebg

+1

@jorgebg Ich nehme an, "Task.WhenAll" behandelt "die Ausnahmen aller einzelnen Aufgaben. Alles, was Sie tun müssen, ist die Ausnahme der zusammengesetzten Task "Task.WhenAll" zurückgeben. So AFAIK, 'warten Task.WhenAll (...)' ist genug. – i3arnon

Verwandte Themen