8

Wszystko, jest wiele pytań na powyższy temat, ale uważam, że jest wystarczająco odmienny, aby uzasadnić nowe pytanie. Mam następujące Task i kontynuację do czynienia z różnych zadań Status; TaskStatus.RanToCompletion, TaskStatus.Canceled i oczywiście AggregateException przez TaskStatus.Faulted. Kod wyglądaObsługa licencji TPL i wyjątków

Task<bool> asyncTask = Task.Factory.StartNew<bool>(() => 
    asyncMethod(uiScheduler, token, someBoolean), token); 

asyncTask.ContinueWith(task => 
{ 
    // Check task status. 
    switch (task.Status) 
    { 
     // Handle any exceptions to prevent UnobservedTaskException.    
     case TaskStatus.RanToCompletion: 
      if (asyncTask.Result) 
      { 
       // Do stuff... 
      } 
      break; 
     case TaskStatus.Faulted: 
      if (task.Exception != null) 
       mainForm.progressRightLabelText = task.Exception.InnerException.Message; 
      else 
       mainForm.progressRightLabelText = "Operation failed!"; 
     default: 
      break; 
    } 
} 

To wszystko działa dobrze, ale obawiam się, czy nie robię z tego prawa, ponieważ istnieje możliwość nastąpienia AggregateException wyrzucane z wnętrza kontynuacji - co wtedy?

Nie chcę Wait na moim asyncTask ani kontynuacji, ponieważ spowoduje to zablokowanie powrotu do wątku interfejsu użytkownika. Aby wychwycić wszystkie wyjątki generowane od wewnątrz kontynuacji nie znaczy, że muszę zrobić coś takiego na pewno

Task parentTask = Task.Factory.startNew(() => 
    { 
     Task<bool> asyncTask = Task.Factory.StartNew<bool>(() => 
      asyncMethod(uiScheduler, token, someBoolean), token); 

     Task continueTask = asyncTask.ContinueWith(task => 
      { 
       // My continuation stuff... 
      } 

     try 
     { 
      continueTask.Wait(); 
     } 
     catch(AggregateException aggEx) 
     { 
      // Some handling here... 
     } 
    }); 

byłoby to jeszcze działa? Jaka jest tutaj najlepsza praktyka?

Jak zawsze, dziękuję za poświęcony czas.

+0

Widziałem zadania, które "biegły do ​​końca", gdy w rzeczywistości rzuciły wyjątek AggregateException. Ten rodzaj obsługi błędów nie działa. Dlaczego po prostu nie użyć funkcji "próbuj/złap"? –

+0

Masz na myśli metodę, która jest wywoływana w wątku tła lub w rzeczywistej metodzie delegowania kontynuacji? – MoonKnight

Odpowiedz

12

Ty może użyciu tradycyjnej try/catch wewnątrz swoich delegatów obserwując AggregateException lub można łańcuch na konkretnych kontynuacje, które będą uruchamiane tylko wtedy, gdy kiedykolwiek poprzednik został przerwana za pomocą opcji TaskContinuationOptions.OnlyOnFaulted. To drugie podejście umożliwia zdefiniowanie bardzo czystych przepływów zadań. Na przykład:

Task myRootTask = ....; 

myRootTask.ContinueWith(rootAntecdent => 
{ 
    // this will only be executed if the antecedent completed successfully, no need to check for faults 
}, 
TaskContinuationOptions.OnlyOnRanToCompletion); 

myRootTask.ContinueWith(rootAntecedent => 
{ 
    // this will only be executed if the antecedent faulted, observe exception and handle accordingly 
}, 
TaskContinuationOptions.OnlyOnFaulted); 
2

MSDN ma dość dobrze napisane „Jak” na temat: here

Można zauważyć, że po prostu użyć try/catch(AggregateException) blok, a następnie filtrować wyjątek wiedzą, jak radzić sobie w ae.Handle(lambda) i zrobić przystanek aplikacji jeśli są pewne, które nie są obsługiwane.

+0

Jestem świadomy takich przykładów, jak te, które oferuje łącze, i nie ma problemu z obsługą odbioru w ten sposób. Mój problem polega na tym, jak radzić sobie z wyjątkami wyrzuconymi z kontynuacji, nie obejmując całego delegata kontynuacyjnego przy próbie catch, a potem znowu to może być jedyny sposób. Chcę poznać najlepsze warunki dla kodu świata rzeczywistego, a nie najlepsze praktyki z zakresu kodów zabawek firmy Microsoft. Twoje zdrowie. – MoonKnight

+0

+1 dla linku. Bardzo przydatne – SleepyBoBos

+0

OP chce wiedzieć, jak to zrobić bez korzystania z Wait. Wszystkie przykłady Zaczekaj na zadanie. Wypróbuj ten link [http://msdn.microsoft.com/en-us/library/dd997415.aspx]. –