c# - 为什么我无法捕获返回类型为 void 的异步函数中的异常?

标签 c# .net async-await

static void Main(string[] args) {
   try {
      var a = MyMethodAsync();
      a.Wait();  // calling Wait throw an AggregateException 
   }
   catch (Exception e) {
      Console.WriteLine("Catch");
   }

   Console.ReadLine();
}

static async Task<String> MyMethodAsync() {    
   String s = await TestThrowException();    
   return s;
}

static Task<String> TestThrowException() {
   return Task.Run(() => {
      throw new DivideByZeroException();
      return "placeholder";   // return statement is needed for the compilier to work correctly
   });
}

上面的代码有效,Main 方法中的 catch block 可以捕获 AggregateException 异常(源自 TestThrowException 并转换为 AggregateException) .

但是如果我有这样的代码:

static void Main(string[] args) {
   try {
      MyMethodAsync(); 
   }
   catch (Exception e) {
      Console.WriteLine("Catch");
   }
   Console.ReadLine();
}

static async void MyMethodAsync() {
   await TestThrowException();
}

static Task<String> TestThrowException() {
   return Task.Run(() => {
      throw new DivideByZeroException();
      return "placeholder";   
}

那么Main方法中的catch block 就捕获不到任何异常,这是为什么呢?

最佳答案

任何时候你有 async void,你基本上打破了正确指示完成 失败的能力;它可以报告失败的唯一方式是异常立即发生并且在任何未完成的await之前发生 - 即同步发生。在您的情况下,Task.Run 保证这是同步的,因此任何关于结果和失败的知识:都将丢失。

从根本上说,永远不要写async void(除非您绝对必须这样做,例如在事件处理程序中)。除了上述问题之外,它已知一些 SynchronizationContext 实现(尤其是遗留的 ASP.NET 实现)的复杂性,这意味着只需调用一个 async void 方法足以使您的应用程序崩溃(至少在假设上;同步上下文警告更适用于库作者而不是应用程序作者,因为库作者无法选择应用程序执行环境)。

移除async void。如果你想返回“nothing”,那么你应该使用 async Taskasync ValueTask 作为签名:

static async Task MyMethodAsync() {
   await TestThrowException();
}

(也许也可以简化为)

static Task MyMethodAsync()
    => TestThrowException();

和:

static async Task Main(string[] args) {
   try {
      await MyMethodAsync(); 
   }
   catch (Exception e) {
      Console.WriteLine("Catch");
   }
   Console.ReadLine();
}

关于c# - 为什么我无法捕获返回类型为 void 的异步函数中的异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67704898/

相关文章:

c# - WPF/C# 不要阻塞 UI

.net - 从F#调用DateTime.TryParse的正确方法是什么?

c# - 取消任务时的 OperationCanceledException VS TaskCanceledException

javascript - Node.js assert.throws 带有异步函数(Promises)

c# - "Cannot locate Resource "themes.xxx.xaml ""运行时错误 - 另一个程序集中的 WPF 自定义组件

c# 任何很酷的图形库来绘制性能数据?

c# - PrintNormal() 问题 'It is not Initialized'

c# - 在运行时访问资源

c# - 为什么不能将 null 用作 Dictionary<bool?, string> 的键?

javascript - 在类中使用 async await 来分配属性但返回 null