以下行为仅在使用Debug
配置(未优化代码)时发生。当我将配置更改为Release
或勾选“构建属性”中的“优化代码”复选框时,它可以正常工作。
我正在尝试使用Task.ContinueWith
中的var task = Task.Factory.StartNew(() => { throw new Exception("Oops"); });
task.ContinueWith(t => { Console.WriteLine(t.Exception.Message); },
TaskContinuationOptions.OnlyOnFaulted);
来解决使用var task = Task.Factory.StartNew(() => { throw new Exception("Oops"); });
task.ContinueWith(t =>
{
if (task.IsFaulted) Console.WriteLine(task.Exception.Message);
});
的任务中发生的异常,但不会处理异常。 this answer
您可以使用以下代码重现:
enum
我也尝试了以下内容:
{{1}}
知道为什么不处理异常吗?
答案 0 :(得分:3)
在评论中扩展我们的讨论:
这里有一个用户未处理的异常(不要与未观察到的异常混淆)导致调试器中断。如果您在没有实际附加调试器的情况下运行调试内置的程序,它应该完全按照您的预期运行。继续将运行,它将观察来自先行任务的异常。
从您的角度来看,您正在处理异常,如果您要编写一些类似于此的香草同步代码:
try
{
throw new Exception("Oops");
}
catch
{
}
...然后调试器足够聪明,可以确定异常确实已经处理完毕,并将其视为处理。
但是,当您处理任务延续时,没有类似的强有力的保证您的异常处理代码将运行。它可以在同一个线程或不同的线程上同步或异步运行,如果延续无法运行,甚至根本不运行(这可能由于运行时无法控制的多种原因而发生)。因此,安全的选择是让调试器说“我不能在即时调用堆栈中的任何地方看到此异常,因此它是用户未处理的"。
要将这一点推向家庭,请考虑未观察到的任务异常。在.NET 4.0中,他们可以在实际抛出后将您的程序拆分为分钟。这就是运行时花费多长时间以合理的信心确定没有任务延续实际查看异常。当您进行调试时,您不能等待那么久。如果看起来未处理,安全选择是让调试器立即中断。
最后,我要注意你可以通过告诉Visual Studio的调试器不要破坏特定的异常类型来修改这种行为(OperationCanceledException
是一个很好的候选者,因为它出现在异步代码中很多)通过调试 - > Windows - >例外设置。
答案 1 :(得分:1)
具有抛出异常的Continuation的任务将异常包装为AggregateException
。如果您检查InnerException
,您会看到它包含"糟糕"
有关详细信息,请参阅Exception Handling in TPL