Wyjątek wewnątrz wyrażenia lambda
Jeśli powstanie wyjątek wewnątrz wyrażania lambda, która jest wywoływana wewnątrz nowego obiektu Task
, wówczas nie jest możliwe przechwycenie tego wyjątku na zewnątrz, poza tym wyrażeniem lambda. Poniżej przykład takiej sytuacji.
Definiujemy metodę, która w obiekcie Task
asynchronicznie odpala operację, która generuje wyjątek.
private static Task DoDangerousThingInNewTask() { return Task<int>.Factory.StartNew(() => { SimpulateLongRunningAsync(); throw new Exception("the intentional exception"); }); }
W kolejnej metodzie wywołujemy tę metodę DoDangerousThingInNewTask
i próbujemy przechwycić wyjątek.
private static async void DoSafeThingAsync() { try { await DoDangerousThingInNewTask(); Console.WriteLine("next calculations and logic"); } catch (Exception ex) { Console.WriteLine(ex); } }
Niestety, powyższy kod nie wykona się poprawnie. Wyjątek, który powstał w metodzie DoDangerousThingInNewTask
nie zostanie przechwycony w klauzurze catch
w metodzie DoSafeThingAsync
.
Wyjątek wewnątrz metody z modyfikatorem async
Inaczej jest w przypadku metod z modyfikatorem async
. Jeśli w metodzie z modyfikatorem async
, zwracającej obiekt typu Task
, wystąpi nieobsłużony wyjątek, wówczas jest on propagowany wyżej do metody wywołującej tę metodę, Zatem, na zewnątrz tej metody z modyfikatorem async
, można użyć konstrukcji try{}catch{}
w celu przechwycenia wyjątku.
Definiujemy metodę z modyfikatorem async
, w której generujemy wyjątek.
private static async Task DoDangerousThingAsync() { await SimpulateLongRunningAsync(); throw new Exception("the intentional exception"); }
W kolejnej metodzie analogicznie jak poprzednio wywołujemy metodę DoDangerousThingAsync
i przechwytujemy wyjątek.
private static async void DoSafeThingAsync() { try { await DoDangerousThingAsync(); Console.WriteLine("next calculations and logic"); } catch (Exception ex) { Console.WriteLine(ex); } }
Tutaj kod wykona się tak, jak byśmy tego oczekiwali. Wyjątek zostanie przechwycony w klauzurze catch
w metodzie DoSafeThingAsync
.