为什么不在GC.Collect上重新抛出任务异常

ima*_*mak 5 c# task c#-4.0

我的理解是当一个Task抛出异常时,当观察到Tasks的(Result,WaitAll)属性或GC发生时,它会被存储并重新抛出.鉴于此,我运行以下代码.

Task t = Task.Factory.StartNew(() =>
{                    
    throw new Exception("Hello World");
});

for (int i = 0; i < 10000; i++)
{
    Console.WriteLine(i);
}    

 GC.Collect();

 for (int a = 20; a < 30; a++)
 {
      Console.WriteLine(a);
 }
Run Code Online (Sandbox Code Playgroud)

但是当我运行上面的代码时,我除了在GC.Collect上抛出一个异常但它没有发生,而是继续从第二个循环打印输出.我的理解在哪里错了?

Nic*_*ler 5

在您的示例代码中,Task对象t仍在范围内,因此在您调用时不符合收集条件GC.Collect().

除此之外,.NET 4.0和.NET 4.5之间的行为也发生了变化:

在.NET 4.0中,未观察到的异常将在终结器线程上引发异常,从而导致进程崩溃.

在.NET 4.5中,此行为已更改,因此默认情况下将忽略未观察到的异常.您可以设置一个配置开关来重新打开旧的严格行为.

.NET 4.0:任务和未处理的异常

.NET 4.5:.NET 4.5中的任务异常处理

  • 另外,请记住在终结器线程上引发异常,而不是调用`GC.Collect()`的线程.如果在`GC.Collect()`之后调用`GC.WaitForPendingFinalizers()`会发生什么? (2认同)

Fur*_*dar 0

因为使用 Task 就像使用 Thread 一样,它是单独执行的(除了主线程之外)。因此,通过这种方式,您可以获得循环输出以及执行的GC.Collect,直到异常行被任务执行为止。