Throwing exceptions from ContinueWith

2019-06-20 21:09发布

I am trying to wrap the exceptions that can be thrown by an async task using ContinueWith(). If I just throw from the continuation action things seem to work, but my debugger claims the exception is unhandled. Am I doing something wrong or is this a Visual Studio problem? Is there a cleaner way to do this, or a way to work around my debugger stopping on what is ultimately a handled exception?

The test below passes and prints "caught wrapped exception as expected", but when I debug it the throw new CustomException line shows as "unhandled by user code".

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");

2条回答
时光不老,我们不散
2楼-- · 2019-06-20 21:21

You don't appear to be "wrapping" the exceptions with a continuation, you seem to be throwing the exception in the continuation. If DoWorkAsync is what can throw an exception, I would "wrap" that in a continuation as follows:

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

Alternatively, if you want to "handle" the exception outside the async method, you could do this:

var task = DoWorkAsync();

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

If you want to transform the thrown exception, you could do something like this:

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

And you could handle that BackoffException like this:

if(task.IsFaulted)
{
   Console.WriteLine(task.Exception.InnerExceptions[0]);
   // TODO: check what type and do something other than WriteLine.
}
查看更多
我想做一个坏孩纸
3楼-- · 2019-06-20 21:34

When "Just My Code" is enabled, Visual Studio in some cases will break on the line that throws the exception and display an error message that says "exception not handled by user code." This error is benign. You can press F5 to continue and see the exception-handling behavior that is demonstrated in these examples. To prevent Visual Studio from breaking on the first error, just uncheck the "Just My Code" checkbox under Tools, Options, Debugging, General.

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

查看更多
登录 后发表回答