2011-07-04 9 views
37

mam jakiś prosty kod jako Repro:Oczekiwanie na zadanie z OnlyOnFaulted Kontynuacja powoduje AggregateException

var taskTest = Task.Factory.StartNew(() => 
{ 
    System.Threading.Thread.Sleep(5000); 

}).ContinueWith((Task t) => 
{ 
    Console.WriteLine("ERR"); 
}, TaskContinuationOptions.OnlyOnFaulted); 

try 
{ 
    Task.WaitAll(taskTest); 
} 
catch (AggregateException ex) 
{ 
    foreach (var e in ex.InnerExceptions) 
     Console.WriteLine(e.Message + Environment.NewLine + e.StackTrace); 
} 

Jednak Dostaję nieoczekiwany TaskCanceledException wyrzucane w bloku try catch (to w Obiekt InnerExceptions AggregateException). "Zadanie zostało anulowane".

Dlaczego otrzymuję ten wyjątek? Kontynuacja zadania nigdy się nie uruchamia, nie było generowanego przez niego wyjątku, ale mimo to mam generowany wyjątek podczas oczekiwania ...

Mam nadzieję, że ktoś może wyjaśnić, jak to ma dla mnie znaczenie:

+0

miałem dokładnie ten sam scenariusz jak ty. Myślę, że byłoby bardziej elegancko i intuicyjnie po prostu propagować wynik poprzedniego zadania. Rzucanie TaskCanceledException było dość zaskakujące ... – NickL

Odpowiedz

53

Nie czekasz na zadanie z kontynuacją OnlyOnFaulted - czekasz na na tej kontynuacji (zwrócony przez ContinueWith). Kontynuacja nigdy nie zostanie uruchomiona, ponieważ pierwotne zadanie powróciło normalnie, więc działa tak, jakby zostało anulowane.

Ma sens dla mnie.

Podejrzewam chcesz utworzyć zadanie, dodaj kontynuację, ale potem czekać na zadaniu oryginalny:

var taskTest = Task.Factory.StartNew(() => 
{ 
    System.Threading.Thread.Sleep(5000); 

}); 
taskTest.ContinueWith((Task t) => 
{ 
    Console.WriteLine("ERR"); 
}, TaskContinuationOptions.OnlyOnFaulted); 
+4

Ahh dobry telefon ... Myślałem, że ContinueWith zwrócił oryginalne zadanie ... – Redth

+0

Świetne wyjaśnienie, tylko jeden komentarz, w tym przypadku prawdopodobnie lepiej nie używać Factory.StartNew(), ponieważ zadanie może zostać uruchomione przed zdefiniowaniem kontynuacji. Tutaj użyłbym nowego Task() ctor, następnie ustaw ContinueWith() i wreszcie wywołaję metodę Start(). Czy jest sens? –

+1

@JorgeFioranelli: Dlaczego wystąpiłoby problem z uruchomieniem zadania przed zdefiniowaniem kontynuacji? Uważam, że TPL poradzi sobie z tym bez żadnych problemów. –