假设我们有两个按钮点击:
private void button2_Click(object sender, EventArgs e)
{
using (
System.Threading.Tasks.Task t = new System.Threading.Tasks.Task(() => {
throw new Exception("puzzle");
}))
{
t.Start();
}
}
private void button3_Click(object sender, EventArgs e)
{
System.Threading.Tasks.Task t = new System.Threading.Tasks.Task(() => {
throw new Exception("puzzle");
});
t.Start();
}
如果在没有调试的情况下使用这两个事件处理程序运行程序,那么button2_Click会立即显示错误消息。但button3_Click不会立即显示错误消息。我有一个印象,如果Task被垃圾收集,那么它会抛出异常。如果Task没有被垃圾收集,那么会生成异常,但仍然存在于一些有趣的地方。我试图在MSDN上找到一些很好的例子,但不是很幸运。
答案 0 :(得分:3)
我可以看到从其他按钮处理程序抛出错误。如果您在VS IDE中启用仅我的代码(工具 - >选项 - >调试 - >一般),这将是显而易见的
在我解释为什么你可以从button2
处理程序看到错误以及为什么不从button3
看到错误之前,了解.NET如何处理任务异常是有意义的。
首先,您的两个Task
操作都会抛出代码中的unhandled
异常行为。当涉及到Task
时,用户代码抛出的任何unhandled exceptions
都会以AggregateException
的形式传播回调用线程;只有当您Wait
Task
(例如异常)或调用Result
来获取输出时,才会引发此异常。在你的情况下,你没有做这些中的任何一个,因此你的例外不被注意。但是这些异常仍然存在,直到任务garbage collected
并且将根据.NET异常策略升级。如果要覆盖异常升级,则需要查看TaskScheduler.UnobservedTaskException
。
现在回到你的处理程序;
如果是button2:您要求在启动任务后立即执行确定性销毁(using block
)。这意味着,您的任务可能位于WaitingToRun
,WaitingForActivation
,RunningRunning
等状态。根据MSDN,只有在任务处于完成状态(RanToCompletion, Faulted or Canceled
)时才可以处置该任务。 话虽如此,异常在所有情况下可能并不明显,因为它取决于您的任务状态以及确定性破坏开始的时刻。
如果是button3:您没有自行处理Task
并将其留给垃圾收集器为您执行此操作。这就是为什么你看不到任何异常的原因。我希望你能清楚地知道如何处理异常。
MSDN详细解释了如何在.NET中处理TASK异常,并涵盖多种场景。
答案 1 :(得分:1)
我用VS2015测试了你的代码,使用button2,我得到了例外:
System.InvalidOperationException: A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled).
任务处于故障状态是正确的。
使用button3,我什么也没得到。这也是正确的行为:t.start()
不是块调用,函数button3_Click
简单结束。如果等待该任务,则会收到AggregateException异常。 Exceptions are propagated when you use one of the static or instance Task.Wait or Task.Wait methods。