2014-07-21 10 views
7

Jestem nowym do C# i znajdę wyjątki nieco mylące ... Mam aplikację z następującego kodu:TimeoutException, TaskCanceledException C#

try 
{ 
    //do something 
} 
catch (TimeoutException t) 
{ 
    Console.WriteLine(t); 
} 
catch (TaskCanceledException tc) 
{ 
    Console.WriteLine(tc); 
} 
catch (Exception e) 
{ 
    Console.WriteLine(e); 
} 

Kiedy debugowania kodu, to rzuca e Exception, najbardziej ogólny i po najechaniu na informację o wyjątku okazuje się, że jest to TaskCanceledException. Dlaczego nie zostało złapane TaskCanceledException? Jeśli wyjątek byłby TimeoutException, czy złapałby on TimeoutException, czy też złapałby Exception? Dlaczego?

+3

Czy jesteś pewien, że nie jest to 'AggregationException' wyrzucony z' obiektu Task'? pokaż nam wywołanie rzucania –

+0

... tak, jest to wyjątek System.AggregateException i InnerException jest wyjątkiem System.Threading.Task.TaskCanceledException. – Marta

Odpowiedz

6

Po złapaniu numeru Exception należy się upewnić, że jest to wyjątek określony jako .. Podczas korzystania z Task.Run lub Task.Factory.Startnew i generalnie z udziałem wyjątku wyrzucanego z Task (chyba że zadanie jest oczekiwane ze słowem kluczowym await), wyjątek zewnętrzny, z którym masz do czynienia, to AggregateException, ponieważ jednostka Task może mieć zadania podrzędne, które mogą także zgłaszaj wyjątki.

Od Exception Handling (Task Parallel Library):

Nieobsłużone wyjątków, które są generowane przez kod użytkownika, który jest uruchomiony wewnątrz zadania są propagowane z powrotem do wątku łączącego, z wyjątkiem niektórych scenariuszach, które są opisane w dalszej części tego tematu. Wyjątki są propagowane podczas korzystania z jednej metody statycznej lub instancji Task.Wait lub TaskWait, a użytkownik obsługuje je, dołączając wywołanie w instrukcji try-catch. Jeśli zadanie jest rodzicem dołączonych zadań podrzędnych lub jeśli czekasz na wiele zadań, może zostać zgłoszonych kilka wyjątków od . Aby propagować wszystkie wyjątki z powrotem do wątku wywołującego, infrastruktura zadania opakowuje je w instancję AggregateException . Wyjątek AggregateException ma właściwość InnerExceptions , którą można wyliczyć w celu zbadania wszystkich oryginalnych wyjątków, które zostały zgłoszone, i obsługiwać (lub nie obsługiwać) każdego z nich oddzielnie. Nawet jeśli zostanie zgłoszony tylko jeden wyjątek, jest on nadal zawijany w wyjątek AggregateException.

Tak, aby sobie z tym poradzić, trzeba złapać AggregateException:

try 
{ 
    //do something 
} 
catch (TimeoutException t) 
{ 
    Console.WriteLine(t); 
} 
catch (TaskCanceledException tc) 
{ 
    Console.WriteLine(tc); 
} 
catch (AggregateException ae) 
{ 
    // This may contain multiple exceptions, which you can iterate with a foreach 
    foreach (var exception in ae.InnerExceptions) 
    { 
     Console.WriteLine(exception.Message); 
    } 
} 
catch (Exception e) 
{ 
    Console.WriteLine(e); 
} 
+0

Ok. Teraz moja aplikacja powinna przestać działać, ale zamiast wyjątku TimeoutException dostaję ten wyjątek AggregateException z wyjątkiem TaskCanceledException. W jaki sposób uzyskać program do wychwytywania TimeoutException? – Marta

+0

zasadniczo jest możliwe, aby rzucić wyjątek TimeoutException zamiast TaskCanceledException? – Marta

+0

Nie, nie jest to możliwe. Wyrażenie 'AggregateExcception' jest generowane z' Task', ponieważ może również zawierać zadania podrzędne. To po prostu opakowanie. –