简体   繁体   English

为什么我无法在具有 void 返回类型的异步 function 中捕获异常?

[英]why I couldn't catch the exception in async function that has void return type?

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
   });
}

The code above works, the catch block in Main method can catch the AggregateException exception (originate from TestThrowException and get converted into AggregateException ).上面的代码有效,Main 方法中的 catch 块可以捕获AggregateException异常(源自TestThrowException并转换为AggregateException )。

But if I have the code like this:但如果我有这样的代码:

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";   
}

then the catch block in Main method cannot catch any exception, why is that?那么 Main 方法中的 catch 块无法捕获任何异常,这是为什么呢?

Any time you have async void , you're basically breaking the ability to correctly signal completion and failure;任何时候你有async void ,你基本上就破坏了正确发出完成失败信号的能力; the only way it can report failure is if the exception happens immediately and before any incomplete await - ie synchronously.它可以报告失败的唯一方法是如果异常立即发生并且在任何不完整的await之前发生 - 即同步发生。 In your case, the Task.Run guarantees that this is not synchronous, hence any knowledge of the outcome and failure: is lost.在您的情况下, Task.Run保证这不是同步的,因此任何关于结果和失败的知识:都会丢失。

Fundamentally, never write async void (unless you absolutely have to, for example in an event-handler).从根本上说,永远不要写async void (除非你绝对必须,例如在事件处理程序中)。 In addition to the problem above, it also has known complications with some SynchronizationContext implementations (in particular the legacy ASP.NET one), which means simply invoking an async void method is enough to crash your application (at least hypothetically; the sync-context caveat applies more to library authors than application authors, since library authors don't get to choose the application execution environment).除了上述问题之外,它还存在一些SynchronizationContext实现的已知复杂性(特别是旧版 ASP.NET 之一),这意味着只需调用async void方法就足以使您的应用程序崩溃(至少假设;同步上下文警告适用库作者比应用程序作者更多,因为库作者没有选择应用程序执行环境)。

Remove the async void .删除async void If you want to return "nothing", then you should use async Task or async ValueTask as the signature:如果你想返回“nothing”,那么你应该使用async Taskasync ValueTask作为签名:

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

(which could perhaps also be simplified to) (也许也可以简化为)

static Task MyMethodAsync()
    => TestThrowException();

and:和:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我不能从异步代码中捕获异常? - Why can't I catch an exception from async code? C#我想用out参数传递一个函数,不能使用数据类型void? - C# I thought to pass a function using the out parameter, data type void couldn't be used? 如何捕获异步void方法异常? - How to catch async void method exception? 捕获由 async void 方法抛出的异常 - Catch an exception thrown by an async void method 为什么我无法捕获此异常? - Why i can't catch this Exception? 在 C# 中,为什么我不能从其接口签名将基接口类型作为其返回类型的 function 返回派生接口类型? - In C#, why can't I return a derived interface type from a function whose interface signature has the base interface type as its return type? 从等待的异步函数中捕获异常 - catch exception from awaited async function 在Azure函数中捕获异步方法异常 - Catch Async Method exception in Azure function 如何将从异步函数引发的异常传播到正在等待的异步void函数? - How can I propagate an exception thrown from an asynchronous function to an awaiting async void function? 是否有可能让 C# 异步方法返回类型不是任务<T>还是无效? - Is it possible to have C# async method return type to be something not Task<T> or void?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM