[英]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 Task
或async 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.