2012-07-26 13 views
5

Próbuję zawijać wyjątków, które mogą być zgłaszane przez zadanie async przy użyciu ContinueWith(). Jeśli po prostu wyrzucę z działania kontynuacyjnego, rzeczy wydają się działać, ale mój debugger twierdzi, że wyjątek jest nieobsługiwany. Czy robię coś złego, czy jest to problem Visual Studio? Czy istnieje lepszy sposób na zrobienie tego, czy sposób obejścia mojego debuggera zatrzymujący się na tym, co jest ostatecznie obsługiwanym wyjątkiem?Wyrzucanie wyjątków z Kontynuuj

Poniższy test kończy się i drukuje "przechwycony wyjątek w opakowaniu zgodnie z oczekiwaniami", ale po debugowaniu linia throw new CustomException wyświetla się jako "nieobsługiwana przez kod użytkownika".

var task = DoWorkAsync().ContinueWith(t => { 
    throw new CustomException("Wrapped", t.Exception.InnerException); // Debugger reports this unhandled 
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously); 

try { 
    task.Wait(); 
    Assert.Fail("Expected work to fail"); 
} catch (AggregateException ag) { 
    if (!(ag.InnerException is CustomException)) 
     throw; 
} 
Console.WriteLine("Caught wrapped exception as expected"); 

Odpowiedz

9

Gdy włączony jest "Just My Code", Visual Studio w niektórych przypadkach przerwie linię, która zgłasza wyjątek i wyświetla komunikat o błędzie "wyjątek nie jest obsługiwany przez kod użytkownika". Ten błąd jest łagodny. Możesz nacisnąć klawisz F5, aby kontynuować i zobaczyć zachowanie związane z obsługą wyjątków, które zostało zademonstrowane w tych przykładach. Aby uniemożliwić programowi Visual Studio złamanie pierwszego błędu, odznacz pole wyboru "Just My Code" w obszarze Tools, Options, Debugging, General.

Od http://msdn.microsoft.com/en-us/library/dd997415.aspx

4

Wygląda na to, że nie wydajesz się "owijać" wyjątkami kontynuacją, ale wydajesz się, że rzucasz wyjątek w kontynuacji. Jeśli DoWorkAsync jest to, co może rzucić wyjątek, chciałbym „wrap”, że w kontynuacji następująco:

DoWorkAsync().ContinueWith(t=>{ 
Console.WriteLine("Error occurred: " + t.Exception); 
}, TaskContinuationOptions.OnlyOnFaulted); 

Ewentualnie, jeśli chcesz „obsłużyć” wyjątek poza metody asynchronicznego, można to zrobić:

var task = DoWorkAsync(); 

task.Wait(); 
if(task.Exception != null) 
{ 
    Console.WriteLine("Error occurred: " + task.Exception); 
} 

Jeśli chcesz przekształcić rzucony wyjątek, można zrobić coś takiego:

var task = DoWorkAsync().ContinueWith(t=>{ 
if(t.Exception.InnerExceptions[0].GetType() == typeof(TimeoutException)) 
{ 
    throw new BackoffException(t.Exception.InnerExceptions[0]); 
} 
}, TaskContinuationOptions.OnlyOnFaulted); 

I można obsłużyć tego BackoffException takiego:

if(task.IsFaulted) 
{ 
    Console.WriteLine(task.Exception.InnerExceptions[0]); 
    // TODO: check what type and do something other than WriteLine. 
} 
+0

Kluczem tutaj jest masz dostępu do właściwości Exception (lub mieć wyjątek ponownie rzucony w ramach AggregateException poprzez dostęp właściwość Zadanie .Result (jeśli masz Zadanie ) ... –

+0

DoWorkAsync() może rzucić kilka wyjątków, a ja po prostu próbuję je przetłumaczyć na kilka "CustomException" wyższego poziomu, które będą mniej kłopotliwe w obsłudze kodu wywołującego. aby całkowicie obsłużyć rzeczy teraz Więc szukam do przekształcenia nieudanego zadania w innym nie powiodło się zadanie , gdzie typ ex Cepcja jest inna. – jtb

+0

Jeśli rzucisz wyjątek CustomException, podsystem TPL po prostu zapakuje go w ten sam typ wyjątku AggregateException, który zawija wyjątek generowany z DoWorkAsync. –

Powiązane problemy