2012-03-30 15 views
6

Czytałem dużo o tym, jak radzić sobie z wyjątkami w TPL, ale tak naprawdę nie rozumiem.wyjątek obsługi w Tpl

Weźmy ten przykładowy kod:

var task1 = new Task(() => { throw new Exception("Throw 1"); }); 
var task2 = task1.ContinueWith(t => Console.WriteLine("Catch 1:{0}", t.Exception.Message), 
           TaskContinuationOptions.OnlyOnFaulted); 
var task3 = task2.ContinueWith(t => Console.WriteLine("Continuation")); 

task1.Start(); 
try { 
    task1.Wait(); 
} 
catch (Exception ex) { 
    Console.WriteLine("Wait Exception: {0}", ex.Message); 
} 

Spodziewałem się, aby wydrukować

Catch 1 
Continuation 

Ale pojawia

Catch 1 
Continuation 
Wait Exception 

Oznacza to, że wyjątek jest nadal uważane nieobsługiwany gdy zadanie zostanie zakończone, a finalizator zadań ostatecznie zniszczy aplikację.

Jak obsłużyć wyjątek w ramach kontynuacji, aby finalizator nie rzucił? W tym samym czasie chcę, aby zadanie pozostało w stanie błędu, więc zawijanie zadania w trybie prób/catch nie będzie działać.


Tło jest, że chcę, aby zaimplementować wzorzec zdarzeń asynchronicznej zgodnie here ale z obsługi błędów. Mój pełny kod wygląda następująco

public IAsyncResult Begin(AsyncCallback callback, object state, Action action) { 
    var task1 = new Task(action); 
    var task2 = task1.ContinueWith(t => HandleException(t.Exception), 
            TaskContinuationOptions.OnlyOnFaulted); 
    if (callback != null) { 
     var task3 = task2.ContinueWith(t => callback(t), 
             TaskScheduler.FromCurrentSynchronizationContext()); 
     var task4 = task3.ContinueWith(t => HandleException(t.Exception), 
             TaskContinuationOptions.OnlyOnFaulted); 
    } 

    task1.Start(); 

    return task; 
} 
+0

Myślałem o wywołaniu 't.Wait()' w próbie kontynuacji i ignorowaniu wyjątku. Ale to nie zadziała, ponieważ kontynuacja może być wykonana po innych rzutach 'Wait()'. – svick

Odpowiedz

3

zrobić swoje oczekiwania na zadania, które nie powiedzie się, a jeśli czytasz documentation on Task.Wait dokładnie widać, że oczekiwania będzie przekaż wyjątek w tym przypadku.

Ale jeśli czekasz na swoje task3 wszystko powinno działać zgodnie z oczekiwaniami.

Oczywiście należy pamiętać o tym:

Podczas korzystania z opcji OnlyOnFaulted, jest gwarantowane, że nieruchomość Wyjątek w poprzedniku nie jest null. Możesz użyć tej właściwości , aby wychwycić wyjątek i zobaczyć, który wyjątek spowodował błąd zadania . Jeśli nie uzyskasz dostępu do właściwości wyjątku, wyjątek zostanie usunięty. Ponadto, jeśli spróbujesz uzyskać dostęp do właściwości wyniku, który został anulowany lub ma błąd, zostanie zgłoszony nowy wyjątek .

(Reference here)

I wreszcie jeszcze inny dobrym źródłem na How to handle exceptions thrown by tasks

Mam nadzieję, że to pomaga.

+1

Myślę, że rozumiem. Zaczekaj zawsze spowoduje wyjątek, nawet jeśli mam dostęp do właściwości .Exception. Jednak dostęp do wyjątku .Exception zmienia wyjątek tak, aby nie był "nieobsługiwany", aby finalizator zadań nie wyrzucił. Szybki test zdaje się potwierdzać dokładnie to. Dzięki – adrianm

Powiązane problemy