为什么第一行代码会立即显示错误消息,但第二行不会?

3
假设我们有两个按钮点击事件:
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上找到一些好的示例,但运气不太好。

什么是错误信息? - Ehsan Sajjad
当您使用Task.Run时,这种情况是否仍会发生? - Abion47
如果您在button3_Click处理程序中最后添加t.Dispose();这一行,您是否会得到异常? - Fredrik Lundvall
如果添加等待和释放,则会生成错误消息。 - Yuriy Zaletskyy
2个回答

3
我可以看到其他按钮处理程序中会抛出错误。如果您在VS IDE(工具->选项->调试->常规)中启用仅限我的代码,那么这对您来说将很明显。
在我解释为什么您可以从button2处理程序中看到错误而不是从button3中看到之前,了解.NET如何处理任务异常是有意义的。
首先,你的两个“任务”操作都会抛出异常,但这些异常却没有被你的代码处理。对于“任务”,任何由用户代码引发的“未处理异常”都会以“聚合异常”的形式传播回调用线程;而这个异常只有在你“等待”该“任务”(在这种情况下引发异常)或调用其“结果”以获取输出时才会引发。在你的情况下,你既没有做其中任何一个,因此你的异常被忽略了。但是这些异常仍然存在,直到任务被“垃圾收集”,并且将根据.NET异常策略升级。如果要覆盖异常升级,则需要查看“TaskScheduler.UnobservedTaskException”。
现在回到你的处理程序; 对于按钮2的情况:您要求在启动任务后立即执行确定性销毁(using block)。这意味着,您的任务可能处于WaitingToRunWaitingForActivationRunningRunning等状态。根据MSDN的说法,只有当任务处于完成状态(RanToCompletion,Faulted或Canceled)时,才可以处理任务。话虽如此,在某些情况下,异常可能并不明显,因为它取决于您的任务状态以及确定性销毁开始的时间。 对于按钮3的情况:您没有自己处理Task的处理,而是让垃圾收集器为您执行。这就是为什么您看不到任何异常的原因。我希望您清楚地了解异常是如何为您处理的。

MSDN详细解释了.NET中如何处理TASK异常,并涵盖了多种情况。


1

我使用VS2015测试了你的代码,在点击button2时出现了异常:

System.InvalidOperationException: A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled).

由于任务处于错误状态,因此这是正确的。

使用按钮3,我什么也没有得到。这也是正确的行为:t.start()不是一个阻塞调用,函数button3_Click只是简单地结束了。如果你等待那个任务,你会得到AggregateException异常。当你使用其中一个静态或实例Task.Wait或Task.Wait方法时,异常会被传播


你有没有在调试模式下测试过它? - Yuriy Zaletskyy
1
已测试过调试和发布版本。 - Matt
抱歉表述不清。我是指在“无调试运行”模式下进行测试。 - Yuriy Zaletskyy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接