首页 > 解决方案 > 为什么带有异常的异步任务会成功完成?

问题描述

我有一个 C# 控制台应用程序,其中包含许多异步任务。其中一项任务是引发异常。但是,我了解到主机代码没有按预期处理场景。为了了解发生了什么,我决定进行一次测试。这个测试的目的是创建一个Task异步运行的,但是,故意抛出一个异常。我想看看返回的内容是否与主机代码的预期相符。

令我惊讶的是,Task对象的IsCompletedSuccessfully属性是true并且IsFaulted属性是false。然而,我期待IsCompletedSuccessfully成为falseIsFaulted成为true。代码如下所示:

[Fact]
public void Repro()
{
  var task = new Task(async () => {
    var operand1 = 2;
    var operand2 = 0;
    var result = operand1 / operand2;
    
    Thread.Sleep(250);
    await Task.CompletedTask;
  });
  
  task.RunSynchronously();
  
  Console.WriteLine($"Cancelled: {task.IsCanceled}, Completed: {task.IsCompleted}, Completed Successfully: {task.IsCompletedSuccessfully}, Faulted: {task.IsFaulted}");
  if (task.Exception != null)
  {
    Console.WriteLine("There was an exception");
  }

  Assert.Equal(false, task.IsCompletedSuccessfully);
  Assert.Equal(true, task.IsFaulted);
}

为什么/如何成功完成此任务?为什么它没有故障?我期待它会引发除以零异常。

谢谢你。

标签: c#asynchronous

解决方案


没有Task采用 a 的构造函数Func<Task>唯一的重载采用Actionor Action<object>

因此,当您编写时new Task(async () => ...),那里的异步 lambda 需要编译为async void方法。

请注意void: 无法将Task备份传播给调用者,这意味着Task构造的 withnew Task(...)仅在 lambda 直接抛出异常时才知道是否存在异常。但是,由于 lambda 是async void,它不会向调用者抛出异常!但是,它会将它们重新扔到线程池中,这会使您的应用程序崩溃。


推荐阅读